diff --git a/API.article.md b/API.article.md new file mode 100644 index 0000000..283270e --- /dev/null +++ b/API.article.md @@ -0,0 +1,181 @@ +# article + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `article.addImage` + +*Source: `src/store/article/addImage.js`* + +Adds an image to an article by its SKU, processing it into AVIF variants. + +```js +const fn = addImage(pool); +const result = await fn(42, 'SKU-1', imageBuffer); +// => { picId, sort, full: { w, h, size }, thumb: { w, h }, fullHash, thumbHash } +``` + +## `article.createUnderParent` + +*Source: `src/store/article/createUnderParent.js`* + +Creates a new article under a given parent category, allocating a SKU and a default unit. + +```js +const fn = createUnderParent(pool); +const article = await fn({ googleAuthId: 42, parentId: 5, name: 'Cola' }); +// => { id, parentId, name, sku } +``` + +## `article.delete` + +*Source: `src/store/article/delete.js`* + +Deletes an article by its SKU, refusing when it still has children. + +```js +const fn = del(pool); +await fn(42, 'SKU-1'); +``` + +## `article.deleteImage` + +*Source: `src/store/article/deleteImage.js`* + +Deletes an image from an article by its SKU and full image hash. + +```js +const fn = deleteImage(pool); +await fn(42, 'SKU-1', 'abc123'); +``` + +## `article.getBySku` + +*Source: `src/store/article/getBySku.js`* + +Returns the full detail of an article by its SKU, including unit, brand, categories, photos, EANs and prices. + +```js +const fn = getBySku(pool); +const article = await fn(42, 'SKU-1'); +// => { article: { id, sku, name, unit, brand, categoryIds, photos, eans, prices, ... } } +``` + +## `article.getHistoryBySku` + +*Source: `src/store/article/getHistoryBySku.js`* + +Returns the change history of an article by its SKU. + +```js +const fn = getHistoryBySku(pool); +const history = await fn(42, 'SKU-1'); +// => [{ id, companyuserId, date, text }] +``` + +## `article.listExport` + +*Source: `src/store/article/listExport.js`* + +Returns articles for export, optionally scoped to a category, including category breadcrumbs and image hashes. + +```js +const fn = listExport(pool); +const articles = await fn(42, 1, null); +// => [{ id, sku, name, slug, unitSi, net, taxRate, eans, categoryBreadcrumbs, fullHashes, ... }] +``` + +## `article.listSearchIndex` + +*Source: `src/store/article/listSearchIndex.js`* + +Returns a lightweight search index of all articles for a company. + +```js +const fn = listSearchIndex(pool); +const articles = await fn(42, 1); +// => [{ id, sku, name, eans, categoryIds }] +``` + +## `article.orderImages` + +*Source: `src/store/article/orderImages.js`* + +Reorders the images of an article by its SKU. + +```js +const fn = orderImages(pool); +const result = await fn(42, 'SKU-1', { fullHashes: ['a', 'b'] }); +// => { fullHashes: ['a', 'b'] } +``` + +## `article.setBrandIdBySku` + +*Source: `src/store/article/setBrandIdBySku.js`* + +Sets (or clears) the brand of an article by its SKU. + +```js +const fn = setBrandIdBySku(pool); +const article = await fn(42, 'SKU-1', 3); +// => { id, sku, name, ... } +``` + +## `article.setCategoryIdsBySku` + +*Source: `src/store/article/setCategoryIdsBySku.js`* + +Replaces the category membership of an article by its SKU. + +```js +const fn = setCategoryIdsBySku(pool); +const article = await fn(42, 'SKU-1', [5, 9]); +// => { id, sku, name, ... } +``` + +## `article.setEansBySku` + +*Source: `src/store/article/setEansBySku.js`* + +Replaces the EAN list of an article by its SKU. + +```js +const fn = setEansBySku(pool); +const article = await fn(42, 'SKU-1', ['4001234567890']); +// => { id, sku, name, ... } +``` + +## `article.setPricesBySku` + +*Source: `src/store/article/setPricesBySku.js`* + +Replaces the price list of an article by its SKU. + +```js +const fn = setPricesBySku(pool); +const article = await fn(42, 'SKU-1', [{ price: 1.5, tax: 19, minmultiplier: 1 }]); +// => { id, sku, name, ... } +``` + +## `article.setWeightBySku` + +*Source: `src/store/article/setWeightBySku.js`* + +Sets the weight of an article by its SKU. + +```js +const fn = setWeightBySku(pool); +const article = await fn(42, 'SKU-1', 1.5); +// => { id, sku, name, ... } +``` + +## `article.updateBySku` + +*Source: `src/store/article/updateBySku.js`* + +Updates an article's name and/or unit (SI and amount), recording history. + +```js +const fn = updateBySku(pool); +const article = await fn(42, 'SKU-1', { name: 'Cola 1L', unitSi: 'l', unitamount: 1 }); +// => { id, sku, name, ... } +``` diff --git a/API.brand.md b/API.brand.md new file mode 100644 index 0000000..5f83177 --- /dev/null +++ b/API.brand.md @@ -0,0 +1,38 @@ +# brand + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `brand.delete` + +*Source: `src/store/brand/delete.js`* + +Deletes a brand for a company by its id. + +```js +const fn = del(pool); +await fn(42, 1, 3); +``` + +## `brand.list` + +*Source: `src/store/brand/list.js`* + +Lists the brands of a company. + +```js +const fn = list(pool); +const brands = await fn(42, 1); +// => [{ id, name, gsprpinfo }] +``` + +## `brand.upsert` + +*Source: `src/store/brand/upsert.js`* + +Creates or updates a brand for a company, keyed by name. + +```js +const fn = upsert(pool); +const brand = await fn(42, 1, { name: 'Coca-Cola', gsprpinfo: 'x' }); +// => { id, name, gsprpinfo } +``` diff --git a/API.category.md b/API.category.md new file mode 100644 index 0000000..501534b --- /dev/null +++ b/API.category.md @@ -0,0 +1,110 @@ +# category + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `category.addImage` + +*Source: `src/store/category/addImage.js`* + +Adds an image to a category, processing it into AVIF full and thumb variants. + +```js +const fn = addImage(pool); +const result = await fn(42, 5, imageBuffer); +// => { id, fullHash, thumbW, thumbH, thumbHash } +``` + +## `category.createUnderParent` + +*Source: `src/store/category/createUnderParent.js`* + +Creates a new category under a given parent category. + +```js +const fn = createUnderParent(pool); +const category = await fn({ googleAuthId: 42, parentId: 5, name: 'Drinks' }); +// => { id, parentId, sort, name, slug } +``` + +## `category.delete` + +*Source: `src/store/category/delete.js`* + +Deletes a category, refusing to delete the company's root category. + +```js +const fn = del(pool); +await fn({ googleAuthId: 42, id: 5 }); +``` + +## `category.deleteImage` + +*Source: `src/store/category/deleteImage.js`* + +Deletes the image of a category. + +```js +const fn = deleteImage(pool); +const result = await fn(42, 5); +// => { id, thumbW: null, thumbH: null, thumbHash: null } +``` + +## `category.getCategoryArticles` + +*Source: `src/store/category/getCategoryArticles.js`* + +Returns the articles belonging to a single category. + +```js +const fn = getCategoryArticles(pool); +const articles = await fn(42, 5); +// => [{ id, sku, name, ... }] +``` + +## `category.getTreeForCompany` + +*Source: `src/store/category/getTreeForCompany.js`* + +Returns the full category tree for a company together with its articles and the posterminal ids assigned to each category. + +```js +const fn = getTreeForCompany(pool); +const tree = await fn(42, 1); +// => { languageId, tree: [{ id, posterminalIds, ... }], articles: [...] } +``` + +## `category.move` + +*Source: `src/store/category/move.js`* + +Moves a category to a new parent, preventing cycles and cross-company moves. + +```js +const fn = move(pool); +const result = await fn({ googleAuthId: 42, id: 5, parentId: 9 }); +// => { id, parentId, sort } +``` + +## `category.order` + +*Source: `src/store/category/order.js`* + +Reorders the child categories of a given parent. + +```js +const fn = order(pool); +const result = await fn({ googleAuthId: 42, parentId: 5, categoryIds: [3, 1, 2] }); +// => { categoryIds: [3, 1, 2] } +``` + +## `category.rename` + +*Source: `src/store/category/rename.js`* + +Renames a category and updates its slug. + +```js +const fn = rename(pool); +const result = await fn({ googleAuthId: 42, id: 5, name: 'Soft Drinks' }); +// => { id, name, slug } +``` diff --git a/API.company.md b/API.company.md new file mode 100644 index 0000000..7e8e468 --- /dev/null +++ b/API.company.md @@ -0,0 +1,80 @@ +# company + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `company.create` + +*Source: `src/store/company/create.js`* + +Creates a new company together with its root category, POS customer group, default language and tax rates, and links it to the given Google auth user. + +```js +const fn = create(pool); +const company = await fn({ + iso639: 'de', + name: 'Acme', + taxrate: 19, + reducedtaxrate: 7, + googleAuthId: 42, +}); +// => { id, rootCategoryId, languageId, taxrateId, reducedtaxrateId, taxfreerateId, posCustomerGroupId } +``` + +## `company.delete` + +*Source: `src/store/company/delete.js`* + +Deletes a company by its id. + +```js +const fn = del(pool); +await fn(1); +``` + +## `company.getById` + +*Source: `src/store/company/getById.js`* + +Returns a single company by its id. + +```js +const fn = getById(pool); +const company = await fn(1); +// => { id, name, ... } +``` + +## `company.getByName` + +*Source: `src/store/company/getByName.js`* + +Returns a single company by its name. + +```js +const fn = getByName(pool); +const company = await fn('Acme'); +// => { id, name, ... } +``` + +## `company.list` + +*Source: `src/store/company/list.js`* + +Lists the companies accessible to the given Google auth user. + +```js +const fn = list(pool); +const companies = await fn(42); +// => [{ id, name, ... }] +``` + +## `company.update` + +*Source: `src/store/company/update.js`* + +Updates an existing company's name, language and tax rates. + +```js +const fn = update(pool); +const result = await fn(1, { iso639: 'de', name: 'Acme', taxrate: 19, reducedtaxrate: 7 }); +// => { id, rootCategoryId, languageId, taxrateId, reducedtaxrateId, taxfreerateId } +``` diff --git a/API.companysetting.md b/API.companysetting.md new file mode 100644 index 0000000..31acc6f --- /dev/null +++ b/API.companysetting.md @@ -0,0 +1,50 @@ +# companysetting + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `companysetting.delete` + +*Source: `src/store/companysetting/delete.js`* + +Deletes a company setting by key. + +```js +const fn = del(pool); +await fn(42, 1, 'theme'); +``` + +## `companysetting.get` + +*Source: `src/store/companysetting/get.js`* + +Returns a single company setting by key. + +```js +const fn = get(pool); +const setting = await fn(42, 1, 'theme'); +// => { key, value, frontend } +``` + +## `companysetting.list` + +*Source: `src/store/companysetting/list.js`* + +Lists the settings of a company, optionally only frontend-visible ones. + +```js +const fn = list(pool); +const settings = await fn(42, 1, { frontendOnly: true }); +// => [{ key, value, frontend }] +``` + +## `companysetting.set` + +*Source: `src/store/companysetting/set.js`* + +Sets (upserts) a company setting by key. + +```js +const fn = set(pool); +const setting = await fn(42, 1, { key: 'theme', value: 'dark', frontend: true }); +// => { key, value, frontend } +``` diff --git a/API.companyuser.md b/API.companyuser.md new file mode 100644 index 0000000..22f3606 --- /dev/null +++ b/API.companyuser.md @@ -0,0 +1,38 @@ +# companyuser + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `companyuser.add` + +*Source: `src/store/companyuser/add.js`* + +Adds a company user linking a company to a Google auth account. + +```js +const fn = add(pool); +const id = await fn(1, 42); +// => 7 +``` + +## `companyuser.delete` + +*Source: `src/store/companyuser/delete.js`* + +Deletes a company user link by its id. + +```js +const fn = del(pool); +await fn(7); +``` + +## `companyuser.getByEmail` + +*Source: `src/store/companyuser/getByEmail.js`* + +Returns the company user ids associated with the given email address. + +```js +const fn = getByEmail(pool); +const ids = await fn('user@example.com'); +// => [1, 2, 3] +``` diff --git a/API.customergroup.md b/API.customergroup.md new file mode 100644 index 0000000..5046957 --- /dev/null +++ b/API.customergroup.md @@ -0,0 +1,62 @@ +# customergroup + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `customergroup.create` + +*Source: `src/store/customergroup/create.js`* + +Creates a new customer group for a company. + +```js +const fn = create(pool); +const group = await fn(42, 1, { name: 'Wholesale' }); +// => { id, name, sort } +``` + +## `customergroup.delete` + +*Source: `src/store/customergroup/delete.js`* + +Deletes a customer group for a company by its id. + +```js +const fn = del(pool); +await fn(42, 1, 5); +``` + +## `customergroup.list` + +*Source: `src/store/customergroup/list.js`* + +Lists the customer groups of a company. + +```js +const fn = list(pool); +const groups = await fn(42, 1); +// => [{ id, name, sort }] +``` + +## `customergroup.order` + +*Source: `src/store/customergroup/order.js`* + +Reorders the customer groups of a company. + +```js +const fn = order(pool); +const result = await fn(42, 1, { customergroupIds: [3, 1, 2] }); +// => { customergroupIds: [3, 1, 2] } +``` + +## `customergroup.update` + +*Source: `src/store/customergroup/update.js`* + +Updates the name of a customer group for a company. + +```js +const fn = update(pool); +const group = await fn(42, 1, 5, { name: 'Retail' }); +// => { id, name, sort } +``` diff --git a/API.delivery.md b/API.delivery.md new file mode 100644 index 0000000..fcbe41a --- /dev/null +++ b/API.delivery.md @@ -0,0 +1,62 @@ +# delivery + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `delivery.create` + +*Source: `src/store/delivery/create.js`* + +Creates a new delivery for a company with its lines. + +```js +const fn = create(pool); +const delivery = await fn(42, 1, { number: 'D-1', date: '2026-01-01', supplierId: 5, lines: [...] }); +// => { id, number, type, entityId, date, lines: [...] } +``` + +## `delivery.delete` + +*Source: `src/store/delivery/delete.js`* + +Deletes a delivery by its id within a company. + +```js +const fn = del(pool); +await fn(42, 1, 5); +``` + +## `delivery.getById` + +*Source: `src/store/delivery/getById.js`* + +Returns a single delivery by its id within a company. + +```js +const fn = getById(pool); +const delivery = await fn(42, 1, 5); +// => { id, number, type, entityId, date, lines: [...] } +``` + +## `delivery.list` + +*Source: `src/store/delivery/list.js`* + +Lists the deliveries of a company. + +```js +const fn = list(pool); +const deliveries = await fn(42, 1); +// => [{ id, number, type, entityId, date }] +``` + +## `delivery.update` + +*Source: `src/store/delivery/update.js`* + +Updates a delivery's header and/or lines. + +```js +const fn = update(pool); +const delivery = await fn(42, 1, 5, { number: 'D-2', lines: [...] }); +// => { id, number, type, entityId, date, lines: [...] } +``` diff --git a/API.entity.md b/API.entity.md new file mode 100644 index 0000000..d409b77 --- /dev/null +++ b/API.entity.md @@ -0,0 +1,62 @@ +# entity + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `entity.create` + +*Source: `src/store/entity/create.js`* + +Creates a new entity (customer) in a customer group, recording history. + +```js +const fn = create(pool); +const entity = await fn(42, 1, { customergroupId: 5, name: 'Doe', firstName: 'John' }); +// => { id, customergroupId, firstName, name, createdAt, updatedAt } +``` + +## `entity.delete` + +*Source: `src/store/entity/delete.js`* + +Deletes an entity by its id within a company. + +```js +const fn = del(pool); +await fn(42, 1, 5); +``` + +## `entity.getById` + +*Source: `src/store/entity/getById.js`* + +Returns a single entity by its id within a company. + +```js +const fn = getById(pool); +const entity = await fn(42, 1, 5); +// => { id, customergroupId, firstName, name, createdAt, updatedAt } +``` + +## `entity.list` + +*Source: `src/store/entity/list.js`* + +Lists the entities (customers) of a company, optionally filtered by customer group or restricted to the 'customer' role. + +```js +const fn = list(pool); +const entities = await fn(42, 1, { customergroupId: 5 }); +// => [{ id, customergroupId, firstName, name, createdAt, updatedAt }] +``` + +## `entity.update` + +*Source: `src/store/entity/update.js`* + +Updates the name and/or first name of an entity, recording history. + +```js +const fn = update(pool); +const entity = await fn(42, 1, 5, { name: 'Doe', firstName: 'Jane' }); +// => { id, customergroupId, firstName, name, createdAt, updatedAt } +``` diff --git a/API.entityaddress.md b/API.entityaddress.md new file mode 100644 index 0000000..b9d9a8a --- /dev/null +++ b/API.entityaddress.md @@ -0,0 +1,50 @@ +# entityaddress + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `entityaddress.create` + +*Source: `src/store/entityaddress/create.js`* + +Creates a new address for an entity. + +```js +const fn = create(pool); +const address = await fn(42, 1, 5, { addressType: 'billing', street: 'Main St', city: 'Berlin' }); +// => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort } +``` + +## `entityaddress.delete` + +*Source: `src/store/entityaddress/delete.js`* + +Deletes an address of an entity. + +```js +const fn = del(pool); +await fn(42, 1, 5, 9); +``` + +## `entityaddress.list` + +*Source: `src/store/entityaddress/list.js`* + +Lists the addresses of an entity. + +```js +const fn = list(pool); +const addresses = await fn(42, 1, 5); +// => [{ id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }] +``` + +## `entityaddress.update` + +*Source: `src/store/entityaddress/update.js`* + +Updates an address of an entity. + +```js +const fn = update(pool); +const address = await fn(42, 1, 5, 9, { city: 'Hamburg' }); +// => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort } +``` diff --git a/API.entitycontact.md b/API.entitycontact.md new file mode 100644 index 0000000..0add735 --- /dev/null +++ b/API.entitycontact.md @@ -0,0 +1,50 @@ +# entitycontact + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `entitycontact.create` + +*Source: `src/store/entitycontact/create.js`* + +Creates a new contact for an entity. + +```js +const fn = create(pool); +const contact = await fn(42, 1, 5, { contactType: 'email', contact: 'a@b.c' }); +// => { id, entityId, contactType, contact, sort } +``` + +## `entitycontact.delete` + +*Source: `src/store/entitycontact/delete.js`* + +Deletes a contact of an entity. + +```js +const fn = del(pool); +await fn(42, 1, 5, 9); +``` + +## `entitycontact.list` + +*Source: `src/store/entitycontact/list.js`* + +Lists the contacts of an entity. + +```js +const fn = list(pool); +const contacts = await fn(42, 1, 5); +// => [{ id, entityId, contactType, contact, sort }] +``` + +## `entitycontact.update` + +*Source: `src/store/entitycontact/update.js`* + +Updates a contact of an entity. + +```js +const fn = update(pool); +const contact = await fn(42, 1, 5, 9, { contact: 'b@c.d' }); +// => { id, entityId, contactType, contact, sort } +``` diff --git a/API.google_auth.md b/API.google_auth.md new file mode 100644 index 0000000..bb2ddab --- /dev/null +++ b/API.google_auth.md @@ -0,0 +1,84 @@ +# google_auth + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `google_auth.add` + +*Source: `src/store/google_auth/add.js`* + +Adds a new allowed Google auth email. + +```js +const fn = add(pool); +const id = await fn('user@example.com'); +// => 1 +``` + +## `google_auth.getByEmail` + +*Source: `src/store/google_auth/getByEmail.js`* + +Returns a Google auth row by email. + +```js +const fn = getByEmail(pool); +const auth = await fn('user@example.com'); +// => { id, email, ... } +``` + +## `google_auth.getById` + +*Source: `src/store/google_auth/getById.js`* + +Returns a Google auth row by its id. + +```js +const fn = getById(pool); +const auth = await fn(42); +// => { id, email, ... } +``` + +## `google_auth.listAllowedEmails` + +*Source: `src/store/google_auth/listAllowedEmails.js`* + +Lists all allowed Google auth emails. + +```js +const fn = listAllowedEmails(pool); +const emails = await fn(); +// => [{ id, email }] +``` + +## `google_auth.removeAllowedEmail` + +*Source: `src/store/google_auth/removeAllowedEmail.js`* + +Removes an allowed Google auth email. + +```js +const fn = removeAllowedEmail(pool); +await fn('user@example.com'); +``` + +## `google_auth.setProfile` + +*Source: `src/store/google_auth/setProfile.js`* + +Updates the profile (picture, picture binary, sub) of a Google auth user. + +```js +const fn = setProfile(pool); +await fn(42, { picture: 'url', pictureBinary: buffer, sub: 'sub' }); +``` + +## `google_auth.setSelectedCompany` + +*Source: `src/store/google_auth/setSelectedCompany.js`* + +Sets the currently selected company for a Google auth user. + +```js +const fn = setSelectedCompany(pool); +await fn(42, 1); +``` diff --git a/API.lang.md b/API.lang.md new file mode 100644 index 0000000..5d20b48 --- /dev/null +++ b/API.lang.md @@ -0,0 +1,62 @@ +# lang + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `lang.create` + +*Source: `src/store/lang/create.js`* + +Creates a new language by its ISO 639 code. + +```js +const fn = create(pool); +const id = await fn('de'); +// => 1 +``` + +## `lang.delete` + +*Source: `src/store/lang/delete.js`* + +Deletes a language by its id. + +```js +const fn = del(pool); +await fn(1); +``` + +## `lang.ensure` + +*Source: `src/store/lang/ensure.js`* + +Returns the id of a language by ISO code, creating it if it does not exist. + +```js +const fn = ensure(pool); +const id = await fn('de'); +// => 1 +``` + +## `lang.getByIso639` + +*Source: `src/store/lang/getByIso639.js`* + +Returns a language row by its ISO 639 code. + +```js +const fn = getByIso639(pool); +const lang = await fn('de'); +// => { id, iso639 } +``` + +## `lang.list` + +*Source: `src/store/lang/list.js`* + +Lists all languages. + +```js +const fn = list(pool); +const languages = await fn(); +// => [{ id, iso639 }] +``` diff --git a/API.md b/API.md new file mode 100644 index 0000000..f82fa37 --- /dev/null +++ b/API.md @@ -0,0 +1,26 @@ +# LibDashStore API + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each method is an async function that takes a `pool` (mssql connection pool) at construction time and returns a callable function. Methods are grouped by the namespace they are exposed under. + +## Table of Contents + +- [companyuser](API.companyuser.md) +- [company](API.company.md) +- [category](API.category.md) +- [article](API.article.md) +- [lang](API.lang.md) +- [tax](API.tax.md) +- [unit](API.unit.md) +- [companysetting](API.companysetting.md) +- [brand](API.brand.md) +- [customergroup](API.customergroup.md) +- [entity](API.entity.md) +- [entityaddress](API.entityaddress.md) +- [entitycontact](API.entitycontact.md) +- [supplier](API.supplier.md) +- [delivery](API.delivery.md) +- [posterminal](API.posterminal.md) +- [google_auth](API.google_auth.md) +- [pic](API.pic.md) diff --git a/API.pic.md b/API.pic.md new file mode 100644 index 0000000..e792d04 --- /dev/null +++ b/API.pic.md @@ -0,0 +1,27 @@ +# pic + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `pic.getImageByHash` + +*Source: `src/store/pic/getImageByHash.js`* + +Returns the full-size image (AVIF) for a given hash. + +```js +const fn = getImageByHash(pool); +const image = await fn(42, 'abc123'); +// => { buffer, w, h, size, contentType: 'image/avif' } +``` + +## `pic.getThumbByHash` + +*Source: `src/store/pic/getThumbByHash.js`* + +Returns the thumbnail image (AVIF) for a given hash. + +```js +const fn = getThumbByHash(pool); +const thumb = await fn(42, 'abc123'); +// => { buffer, w, h, contentType: 'image/avif' } +``` diff --git a/API.posterminal.md b/API.posterminal.md new file mode 100644 index 0000000..294ac18 --- /dev/null +++ b/API.posterminal.md @@ -0,0 +1,86 @@ +# posterminal + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `posterminal.delete` + +*Source: `src/store/posterminal/delete.js`* + +Deletes a posterminal by its id within a company. + +```js +const fn = del(pool); +await fn(42, 1, 5); +``` + +## `posterminal.list` + +*Source: `src/store/posterminal/list.js`* + +Lists the posterminals of a company. + +```js +const fn = list(pool); +const terminals = await fn(42, 1); +// => [{ id, name, token, pairingpin }] +``` + +## `posterminal.setOff` + +*Source: `src/store/posterminal/setOff.js`* + +Removes a category assignment from a posterminal (turns it off). + +```js +const fn = setOff(pool); +const result = await fn(42, 1, 5, 9); +// => { id, categoryIds: [...] } +``` + +## `posterminal.setOffAll` + +*Source: `src/store/posterminal/setOffAll.js`* + +Removes all category assignments from a posterminal. + +```js +const fn = setOffAll(pool); +const result = await fn(42, 1, 5); +// => { id, categoryIds: [] } +``` + +## `posterminal.setOn` + +*Source: `src/store/posterminal/setOn.js`* + +Assigns a category to a posterminal (turns it on for that category). + +```js +const fn = setOn(pool); +const result = await fn(42, 1, 5, 9); +// => { id, categoryIds: [9, ...] } +``` + +## `posterminal.setOnAll` + +*Source: `src/store/posterminal/setOnAll.js`* + +Assigns all categories of a company to a posterminal. + +```js +const fn = setOnAll(pool); +const result = await fn(42, 1, 5); +// => { id, categoryIds: [...] } +``` + +## `posterminal.upsert` + +*Source: `src/store/posterminal/upsert.js`* + +Creates or updates a posterminal for a company. + +```js +const fn = upsert(pool); +const terminal = await fn(42, 1, { name: 'Kasse 1', pairingpin: '1234', token: 'abc' }); +// => { id, name, token, pairingpin } +``` diff --git a/API.supplier.md b/API.supplier.md new file mode 100644 index 0000000..5abab79 --- /dev/null +++ b/API.supplier.md @@ -0,0 +1,50 @@ +# supplier + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `supplier.create` + +*Source: `src/store/supplier/create.js`* + +Creates a new supplier for a company, recording history. + +```js +const fn = create(pool); +const supplier = await fn(42, 1, { name: 'Acme Supplies' }); +// => { id, name, createdAt, updatedAt } +``` + +## `supplier.delete` + +*Source: `src/store/supplier/delete.js`* + +Deletes a supplier by its id within a company. + +```js +const fn = del(pool); +await fn(42, 1, 5); +``` + +## `supplier.list` + +*Source: `src/store/supplier/list.js`* + +Lists the suppliers of a company. + +```js +const fn = list(pool); +const suppliers = await fn(42, 1); +// => [{ id, name, createdAt, updatedAt }] +``` + +## `supplier.update` + +*Source: `src/store/supplier/update.js`* + +Updates the name of a supplier, recording history. + +```js +const fn = update(pool); +const supplier = await fn(42, 1, 5, { name: 'Acme GmbH' }); +// => { id, name, createdAt, updatedAt } +``` diff --git a/API.tax.md b/API.tax.md new file mode 100644 index 0000000..d6f77c4 --- /dev/null +++ b/API.tax.md @@ -0,0 +1,51 @@ +# tax + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `tax.create` + +*Source: `src/store/tax/create.js`* + +Creates a new tax rate. + +```js +const fn = create(pool); +const id = await fn(19); +// => 1 +``` + +## `tax.ensure` + +*Source: `src/store/tax/ensure.js`* + +Returns the id of a tax rate, creating it if it does not exist. + +```js +const fn = ensure(pool); +const id = await fn(19); +// => 1 +``` + +## `tax.getByRate` + +*Source: `src/store/tax/getByRate.js`* + +Returns a tax row by its rate. + +```js +const fn = getByRate(pool); +const tax = await fn(19); +// => { id, rate } +``` + +## `tax.list` + +*Source: `src/store/tax/list.js`* + +Lists all tax rates. + +```js +const fn = list(pool); +const taxes = await fn(); +// => [{ id, rate }] +``` diff --git a/API.unit.md b/API.unit.md new file mode 100644 index 0000000..7d10790 --- /dev/null +++ b/API.unit.md @@ -0,0 +1,38 @@ +# unit + +This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`. + +## `unit.delete` + +*Source: `src/store/unit/delete.js`* + +Deletes a unit for a company by its SI code. + +```js +const fn = del(pool); +await fn(42, 1, 'l'); +``` + +## `unit.list` + +*Source: `src/store/unit/list.js`* + +Lists the units available for a company. + +```js +const fn = list(pool); +const units = await fn(42, 1); +// => [{ id, si, basesi, basesifactor, symbol, name }] +``` + +## `unit.upsert` + +*Source: `src/store/unit/upsert.js`* + +Creates or updates a unit for a company, keyed by its SI code. + +```js +const fn = upsert(pool); +const unit = await fn(42, 1, { si: 'l', basesi: 'm3', basesifactor: 0.001, symbol: 'L', name: 'Liter' }); +// => { id, si, basesi, basesifactor, symbol, name } +``` diff --git a/README.md b/README.md index fe3db67..f459dcc 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,6 @@ ID fields in the JS API use camelCase `…Id` (DB columns stay snake_case). `goo ## Schema -**Kein Migrations-Code:** Wir gehen von einer frischen DB aus (`npm run reset-db`). Schema nur in `src/schema.js`; Anpassungen an einer laufenden DB manuell per `sqlcmd`, nicht im Repo. - | Method | Description | | --- | --- | | `initialize()` | Runs all `SCHEMA_SCRIPTS` (`IF NOT EXISTS`). Does **not** purge. | diff --git a/generate-api-doc.js b/generate-api-doc.js new file mode 100644 index 0000000..1c4f0fa --- /dev/null +++ b/generate-api-doc.js @@ -0,0 +1,225 @@ +import { readdirSync, readFileSync, writeFileSync, statSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const storeDir = join(__dirname, 'src', 'store'); +const outputPath = join(__dirname, 'API.md'); + +// Modules that are exposed on the LibDashStore instance (from src/index.js). +// Order here controls the order of sections in the generated document. +const MODULE_ORDER = [ + 'companyuser', + 'company', + 'category', + 'article', + 'lang', + 'tax', + 'unit', + 'companysetting', + 'brand', + 'customergroup', + 'entity', + 'entityaddress', + 'entitycontact', + 'supplier', + 'delivery', + 'quote', + 'order', + 'posterminal', + 'google_auth', + 'pic', +]; + +// Files that are internal helpers and should not appear as public API entries. +const INTERNAL_FILES = new Set([ + 'request.js', + 'slugify.js', + 'initialize.js', + 'purge.js', + 'helpers.js', + 'writeLines.js', + 'shapeSetting.js', + 'shapeUnit.js', + 'ensureDefault.js', + 'ensureLieferantenGroup.js', + 'resolveCompanyAccess.js', + 'resolveCategoryAccess.js', + 'resolveCustomerGroupAccess.js', + 'resolveEntityAccess.js', + 'resolvePicAccess.js', + 'resolveArticleBySku.js', + 'queryBySku.js', + 'queryCategoryArticles.js', + 'getCategoryPosterminalIds.js', + 'nextSku.js', + 'createStore.js', + 'index.js', +]); + +/** + * Extract the leading JSDoc block from a source string. + * @param {string} source + * @returns {{ description: string, example: string } | null} + */ +function extractJsDoc(source) { + const match = source.match(/\/\*\*([\s\S]*?)\*\//); + if (!match) return null; + + const block = match[1]; + const lines = block + .split('\n') + .map((l) => l.replace(/^\s*\*\s?/, '').replace(/^\s*\*/, '')); + + const description = []; + const example = []; + let inExample = false; + + for (const line of lines) { + if (line.trim() === '@example') { + inExample = true; + continue; + } + if (line.trim().startsWith('@')) { + inExample = false; + continue; + } + if (inExample) { + example.push(line); + } else if (line.trim()) { + description.push(line.trim()); + } + } + + return { + description: description.join(' ').trim(), + example: example.join('\n').trim(), + }; +} + +/** + * Recursively collect all .js files under a directory. + * @param {string} dir + * @returns {string[]} absolute file paths + */ +function collectFiles(dir) { + const out = []; + for (const entry of readdirSync(dir)) { + const full = join(dir, entry); + if (statSync(full).isDirectory()) { + out.push(...collectFiles(full)); + } else if (entry.endsWith('.js')) { + out.push(full); + } + } + return out; +} + +/** + * Build a map of module name -> array of { name, file, description, example }. + * @returns {Map>} + */ +function buildModules() { + const modules = new Map(); + + for (const file of collectFiles(storeDir)) { + const rel = file.slice(storeDir.length + 1).split('/'); + const moduleName = rel[0]; + const fileName = rel[rel.length - 1]; + + if (INTERNAL_FILES.has(fileName)) continue; + + const source = readFileSync(file, 'utf8'); + const doc = extractJsDoc(source); + if (!doc) continue; + + const fnName = fileName.replace(/\.js$/, ''); + if (!modules.has(moduleName)) { + modules.set(moduleName, []); + } + modules.get(moduleName).push({ + name: fnName, + file: rel.join('/'), + description: doc.description, + example: doc.example, + }); + } + + return modules; +} + +function renderSection(moduleName, entries) { + const lines = []; + lines.push(`# ${moduleName}`); + lines.push(''); + lines.push( + 'This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`.', + ); + lines.push(''); + + for (const entry of entries) { + lines.push(`## \`${moduleName}.${entry.name}\``); + lines.push(''); + lines.push(`*Source: \`src/store/${entry.file}\`*`); + lines.push(''); + if (entry.description) { + lines.push(entry.description); + lines.push(''); + } + if (entry.example) { + lines.push('```js'); + lines.push(entry.example); + lines.push('```'); + lines.push(''); + } + } + + return lines.join('\n'); +} + +function render() { + const modules = buildModules(); + + const ordered = MODULE_ORDER.filter((m) => modules.has(m)); + const extra = [...modules.keys()].filter((m) => !MODULE_ORDER.includes(m)).sort(); + const moduleNames = [...ordered, ...extra]; + + // Write one file per section: API.
.md + const written = []; + for (const moduleName of moduleNames) { + const sectionPath = join(__dirname, `API.${moduleName}.md`); + const markdown = renderSection(moduleName, modules.get(moduleName)); + writeFileSync(sectionPath, markdown, 'utf8'); + written.push({ moduleName, sectionPath, bytes: markdown.length }); + } + + // Write the index API.md linking to each section file. + const lines = []; + lines.push('# LibDashStore API'); + lines.push(''); + lines.push( + 'This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`.', + ); + lines.push(''); + lines.push( + 'The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each method is an async function that takes a `pool` (mssql connection pool) at construction time and returns a callable function. Methods are grouped by the namespace they are exposed under.', + ); + lines.push(''); + lines.push('## Table of Contents'); + lines.push(''); + + for (const { moduleName } of written) { + lines.push(`- [${moduleName}](API.${moduleName}.md)`); + } + + lines.push(''); + + return { index: lines.join('\n'), written }; +} + +const { index, written } = render(); +writeFileSync(outputPath, index, 'utf8'); +console.log(`Wrote ${outputPath} (${index.length} bytes)`); +for (const { moduleName, sectionPath, bytes } of written) { + console.log(`Wrote ${sectionPath} (${bytes} bytes)`); +} diff --git a/package.json b/package.json index e22905f..6809ec3 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "scripts": { "schema-graph": "node generate-schema-graph.js", + "api-doc": "node generate-api-doc.js", "init-schema": "node scripts/init-schema.js", "purge-db": "node scripts/purge-db.js", "reset-db": "node scripts/reset-db.js",