diff --git a/docs/api/README.md b/docs/api/README.md index 1f77c93..4e58f4e 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -276,6 +276,8 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route | [`routes/unit/upsert.md`](routes/unit/upsert.md) | `PUT /unit` | | [`routes/v1/category.md`](routes/v1/category.md) | `GET /v1/category` | | [`routes/pos/client.md`](routes/pos/client.md) | `GET /v1/client` | +| [`routes/v1/customer.md`](routes/v1/customer.md) | `GET /v1/customer` | +| [`routes/v1/customergroup.md`](routes/v1/customergroup.md) | `GET /v1/customergroup` | | [`routes/pos/init.md`](routes/pos/init.md) | `GET /v1/init` | | [`routes/pos/pimage.md`](routes/pos/pimage.md) | `GET /v1/pimage` | | [`routes/v1/product.md`](routes/v1/product.md) | `GET /v1/product` | diff --git a/docs/api/routes-all.md b/docs/api/routes-all.md index 07ce708..5b1fd45 100644 --- a/docs/api/routes-all.md +++ b/docs/api/routes-all.md @@ -1,6 +1,6 @@ # Dash API Routes Overview (All) -Overview of all 264 API endpoints across all modules. +Overview of all 266 API endpoints across all modules. ### Notation @@ -927,6 +927,12 @@ _none_ #### POS discovery and pairing — `GET /v1/client` - Params: `query: authCode: str, name?: str` - Returns: `200 { authCode: str|null, authToken: str|null, certificateFingerprint: str, certificateSerialNumber: str, mandantId: str, mandantName: str|null, mandantDatabase: str|null, serverFingerprint: str|null, name: str|null, serverTimestamp: str }` +#### JTL-POS customer catalog synchronization — `GET /v1/customer` +- Params: `query: lastChangedCustomer?: str, limit?: int` +- Returns: `200 { id: str, customerNumber: str, firstname: str, lastname: str, title: str, company: str, address: str, addressSupplement: str, city: str, postalCode: str, state: str, country: str, phone: str, email: str, customerGroupId: str, salutation: str, birthday: str, discount: str, taxIdNumber: str, lastChanged: str, debtorNumber: str }[]` +#### JTL-POS customer group synchronization — `GET /v1/customergroup` +- Params: `query: lastChangedCustomerGroup?: str, limit?: int` +- Returns: `200 { customerGroupId: str, name: str, standard: str, discountPercent: str, lastChanged: str }[]` #### POS sync initialization counts — `GET /v1/init` - Params: `query: lastChangedProduct?: int, lastChangedCategory?: int, lastChangedCustomer?: int, lastChangedCustomerGroup?: int, lastChangedCompositeProduct?: int, lastChangedDeletedEntity?: int` - Returns: `200 { version: str, product_count: str, category_count: str, customer_count: str, customerGroup_count: str, compositeProduct_count: str, configurationGroup_count: str, configurationItem_count: str, deletedEntity_count: str, max_orderId_count: str }` diff --git a/docs/api/routes/v1/customer.md b/docs/api/routes/v1/customer.md new file mode 100644 index 0000000..bbaf39c --- /dev/null +++ b/docs/api/routes/v1/customer.md @@ -0,0 +1,56 @@ +# `GET /v1/customer` + +Protected. Requires a valid session cookie (`credentials: 'include'`). + +JTL-POS customer catalog synchronization + +Returns customer list modified after lastChangedCustomer cursor for the authenticated POS register. + +## Query parameters + +| Param | Required | Type | Description | +|-------|----------|------|-------------| +| `lastChangedCustomer` | no | string | Unix timestamp cursor of last customer sync | +| `limit` | no | integer | Maximum number of customers to return | + +## Response `200` + +Array of customer objects for JTL-POS + +```json +[ + { + "id": "…", + "customerNumber": "…", + "firstname": "…", + "lastname": "…", + "title": "…", + "company": "…", + "address": "…", + "addressSupplement": "…", + "city": "…", + "postalCode": "…", + "state": "…", + "country": "…", + "phone": "…", + "email": "…", + "customerGroupId": "…", + "salutation": "…", + "birthday": "…", + "discount": "…", + "taxIdNumber": "…", + "lastChanged": "…", + "debtorNumber": "…" + } +] +``` + +## Errors + +| Status | Description | +|--------|-------------| +| 401 | Unauthorized | + +--- + +_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._ diff --git a/docs/api/routes/v1/customergroup.md b/docs/api/routes/v1/customergroup.md new file mode 100644 index 0000000..bd110f7 --- /dev/null +++ b/docs/api/routes/v1/customergroup.md @@ -0,0 +1,40 @@ +# `GET /v1/customergroup` + +Protected. Requires a valid session cookie (`credentials: 'include'`). + +JTL-POS customer group synchronization + +Returns customer groups modified after lastChangedCustomerGroup cursor for the authenticated POS register, excluding 'Lieferanten'. + +## Query parameters + +| Param | Required | Type | Description | +|-------|----------|------|-------------| +| `lastChangedCustomerGroup` | no | string | Unix timestamp cursor of last customer group sync | +| `limit` | no | integer | Maximum number of customer groups to return | + +## Response `200` + +Array of customer group objects for JTL-POS + +```json +[ + { + "customerGroupId": "1", + "name": "Endkunden", + "standard": "1", + "discountPercent": "0.000000", + "lastChanged": "1721000000" + } +] +``` + +## Errors + +| Status | Description | +|--------|-------------| +| 401 | Unauthorized | + +--- + +_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._ diff --git a/scripts/generateApiDocs.js b/scripts/generateApiDocs.js index f715d7d..9443205 100644 --- a/scripts/generateApiDocs.js +++ b/scripts/generateApiDocs.js @@ -42,6 +42,8 @@ const OMITTED_ROUTES = new Set([ 'GET /thumb/{fullHash}', 'GET /v1/category', 'GET /v1/client', + 'GET /v1/customer', + 'GET /v1/customergroup', 'GET /v1/init', 'GET /v1/pimage', 'GET /v1/product', diff --git a/src/db/posterminal.js b/src/db/posterminal.js index bd1a021..7d90d84 100644 --- a/src/db/posterminal.js +++ b/src/db/posterminal.js @@ -70,11 +70,21 @@ export async function getCustomerCount(params) { return store.posterminal.getCustomerCount(params); } +export async function getCustomerList(params) { + const store = await getStore(); + return store.posterminal.getCustomerList(params); +} + export async function getCustomerGroupCount(params) { const store = await getStore(); return store.posterminal.getCustomerGroupCount(params); } +export async function getCustomerGroupList(params) { + const store = await getStore(); + return store.posterminal.getCustomerGroupList(params); +} + export async function getCompositeProductCount(params) { const store = await getStore(); return store.posterminal.getCompositeProductCount(params); diff --git a/src/v1/index.js b/src/v1/index.js index f6765ce..cc62df1 100644 --- a/src/v1/index.js +++ b/src/v1/index.js @@ -3,6 +3,8 @@ import { posAuthMiddleware } from './middleware/posAuth.js'; import { handleClient } from './routes/client.js'; import { handleInit } from './routes/init.js'; import { handleCategory } from './routes/category.js'; +import { handleCustomerGroup } from './routes/customergroup.js'; +import { handleCustomer } from './routes/customer.js'; import { handleProduct } from './routes/product.js'; import { handlePimage } from './routes/pimage.js'; @@ -16,6 +18,8 @@ router.get('/init', posAuthMiddleware, handleInit); // POS master data synchronization router.get('/category', posAuthMiddleware, handleCategory); +router.get('/customergroup', posAuthMiddleware, handleCustomerGroup); +router.get('/customer', posAuthMiddleware, handleCustomer); router.get('/product', posAuthMiddleware, handleProduct); // POS image delivery diff --git a/src/v1/routes/customer.js b/src/v1/routes/customer.js new file mode 100644 index 0000000..e24e4f3 --- /dev/null +++ b/src/v1/routes/customer.js @@ -0,0 +1,96 @@ +import { getCustomerList } from '../../db/posterminal.js'; + +/** + * @openapi + * /v1/customer: + * get: + * summary: JTL-POS customer catalog synchronization + * description: Returns customer list modified after lastChangedCustomer cursor for the authenticated POS register. + * tags: + * - POS Sync + * security: + * - BearerAuth: [] + * parameters: + * - in: query + * name: lastChangedCustomer + * schema: + * type: string + * description: Unix timestamp cursor of last customer sync + * - in: query + * name: limit + * schema: + * type: integer + * default: 20 + * description: Maximum number of customers to return + * responses: + * 200: + * description: Array of customer objects for JTL-POS + * content: + * application/json: + * schema: + * type: array + * items: + * type: object + * properties: + * id: + * type: string + * customerNumber: + * type: string + * firstname: + * type: string + * lastname: + * type: string + * title: + * type: string + * company: + * type: string + * address: + * type: string + * addressSupplement: + * type: string + * city: + * type: string + * postalCode: + * type: string + * state: + * type: string + * country: + * type: string + * phone: + * type: string + * email: + * type: string + * customerGroupId: + * type: string + * salutation: + * type: string + * birthday: + * type: string + * discount: + * type: string + * taxIdNumber: + * type: string + * lastChanged: + * type: string + * debtorNumber: + * type: string + * 401: + * description: Unauthorized + */ +export async function handleCustomer(req, res, next) { + try { + const posterminal = req.posterminal; + const cursor = Number(req.query.lastChangedCustomer) || 0; + const limit = Number(req.query.limit) || 20; + + const customers = await getCustomerList({ + posterminalId: posterminal.id, + cursor, + limit, + }); + + res.json(customers); + } catch (err) { + next(err); + } +} diff --git a/src/v1/routes/customergroup.js b/src/v1/routes/customergroup.js new file mode 100644 index 0000000..dbf7ad6 --- /dev/null +++ b/src/v1/routes/customergroup.js @@ -0,0 +1,69 @@ +import { getCustomerGroupList } from '../../db/posterminal.js'; + +/** + * @openapi + * /v1/customergroup: + * get: + * summary: JTL-POS customer group synchronization + * description: Returns customer groups modified after lastChangedCustomerGroup cursor for the authenticated POS register, excluding 'Lieferanten'. + * tags: + * - POS Sync + * security: + * - BearerAuth: [] + * parameters: + * - in: query + * name: lastChangedCustomerGroup + * schema: + * type: string + * description: Unix timestamp cursor of last customer group sync + * - in: query + * name: limit + * schema: + * type: integer + * default: 50 + * description: Maximum number of customer groups to return + * responses: + * 200: + * description: Array of customer group objects for JTL-POS + * content: + * application/json: + * schema: + * type: array + * items: + * type: object + * properties: + * customerGroupId: + * type: string + * example: "1" + * name: + * type: string + * example: "Endkunden" + * standard: + * type: string + * example: "1" + * discountPercent: + * type: string + * example: "0.000000" + * lastChanged: + * type: string + * example: "1721000000" + * 401: + * description: Unauthorized + */ +export async function handleCustomerGroup(req, res, next) { + try { + const posterminal = req.posterminal; + const cursor = Number(req.query.lastChangedCustomerGroup) || 0; + const limit = Number(req.query.limit) || 50; + + const customerGroups = await getCustomerGroupList({ + posterminalId: posterminal.id, + cursor, + limit, + }); + + res.json(customerGroups); + } catch (err) { + next(err); + } +}