From e085bcaeba460519c3f591f3bdad03872a836bb1 Mon Sep 17 00:00:00 2001 From: seb Date: Wed, 21 Oct 2026 06:13:29 +0200 Subject: [PATCH] u --- API.md | 2 + API.posterminal.md | 40 +++++++++ src/index.js | 4 + src/providers/mssql/queries/posterminal.js | 78 +++++++++++++++++- src/providers/sqlite3/queries/posterminal.js | 82 +++++++++++++++++++ src/store/posterminal/getCustomerGroupList.js | 40 +++++++++ src/store/posterminal/getCustomerList.js | 56 +++++++++++++ 7 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 src/store/posterminal/getCustomerGroupList.js create mode 100644 src/store/posterminal/getCustomerList.js diff --git a/API.md b/API.md index 2a35197..a2305e2 100644 --- a/API.md +++ b/API.md @@ -261,6 +261,8 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met - `getCompositeProductCount(input: {posterminalId: number, cursor?: number}, tx?: object): Promise` - `getCustomerCount(input: {posterminalId: number, cursor?: number}, tx?: object): Promise` - `getCustomerGroupCount(input: {posterminalId: number, cursor?: number}, tx?: object): Promise` + - `getCustomerGroupList(input: {posterminalId: number, cursor?: number, limit?: number}, tx?: object): Promise>` + - `getCustomerList(input: {posterminalId: number, cursor?: number, limit?: number}, tx?: object): Promise>` - `getDeletedEntityCount(input?: {posterminalId?: number, cursor?: number}): Promise` - `getMaxOrderIdCount(input: {posterminalId: number}, tx?: object): Promise` - `getProductCount(input: {posterminalId: number, cursor?: number}, tx?: object): Promise` diff --git a/API.posterminal.md b/API.posterminal.md index 2737f9d..33ede5c 100644 --- a/API.posterminal.md +++ b/API.posterminal.md @@ -160,6 +160,46 @@ Counts customer groups of the POS terminal company updated after the given unix `Promise` — The count of changed records. +## `posterminal.getCustomerGroupList` + +*Source: `src/store/posterminal/getCustomerGroupList.js`* + +Lists customer groups for a POS terminal modified after the cursor, excluding 'Lieferanten'. + +**Parameters** + +| Name | Type | Description | +| --- | --- | --- | +| `input` | `object` | | +| `input.posterminalId` | `number` | The POS terminal id. | +| `[input.cursor=0]` | `number` | Unix timestamp cursor. | +| `[input.limit=50]` | `number` | Max items to return. | +| `[tx]` | `object` | Optional transaction. | + +**Returns** + +`Promise>` + +## `posterminal.getCustomerList` + +*Source: `src/store/posterminal/getCustomerList.js`* + +Lists customers for a POS terminal modified after the cursor, excluding 'Lieferanten'. + +**Parameters** + +| Name | Type | Description | +| --- | --- | --- | +| `input` | `object` | | +| `input.posterminalId` | `number` | The POS terminal id. | +| `[input.cursor=0]` | `number` | Unix timestamp cursor. | +| `[input.limit=20]` | `number` | Max items to return. | +| `[tx]` | `object` | Optional transaction. | + +**Returns** + +`Promise>` + ## `posterminal.getDeletedEntityCount` *Source: `src/store/posterminal/getDeletedEntityCount.js`* diff --git a/src/index.js b/src/index.js index 7f772a9..4f640a1 100644 --- a/src/index.js +++ b/src/index.js @@ -121,7 +121,9 @@ import posterminalPair from './store/posterminal/pair.js'; import posterminalGetProductCount from './store/posterminal/getProductCount.js'; import posterminalGetCategoryCount from './store/posterminal/getCategoryCount.js'; import posterminalGetCustomerCount from './store/posterminal/getCustomerCount.js'; +import posterminalGetCustomerList from './store/posterminal/getCustomerList.js'; import posterminalGetCustomerGroupCount from './store/posterminal/getCustomerGroupCount.js'; +import posterminalGetCustomerGroupList from './store/posterminal/getCustomerGroupList.js'; import posterminalGetCompositeProductCount from './store/posterminal/getCompositeProductCount.js'; import posterminalGetDeletedEntityCount from './store/posterminal/getDeletedEntityCount.js'; import posterminalGetMaxOrderIdCount from './store/posterminal/getMaxOrderIdCount.js'; @@ -481,7 +483,9 @@ export default class LibDashStore { getProductCount: posterminalGetProductCount(provider), getCategoryCount: posterminalGetCategoryCount(provider), getCustomerCount: posterminalGetCustomerCount(provider), + getCustomerList: posterminalGetCustomerList(provider), getCustomerGroupCount: posterminalGetCustomerGroupCount(provider), + getCustomerGroupList: posterminalGetCustomerGroupList(provider), getCompositeProductCount: posterminalGetCompositeProductCount(provider), getDeletedEntityCount: posterminalGetDeletedEntityCount(provider), getMaxOrderIdCount: posterminalGetMaxOrderIdCount(provider), diff --git a/src/providers/mssql/queries/posterminal.js b/src/providers/mssql/queries/posterminal.js index 0c695f7..0fdfa16 100644 --- a/src/providers/mssql/queries/posterminal.js +++ b/src/providers/mssql/queries/posterminal.js @@ -189,10 +189,11 @@ SELECT COUNT(*) AS count FROM entity e INNER JOIN customergroup cg ON cg.id = e.customergroup_id INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = cg.company_id -WHERE cg.name NOT IN ('Lieferanten', 'POS') +WHERE cg.name <> 'Lieferanten' AND DATEDIFF_BIG(second, '1970-01-01', e.updated_at) > @cursor `; + export const COUNT_CUSTOMER_GROUPS = ` SELECT COUNT(*) AS count FROM customergroup cg @@ -387,6 +388,80 @@ WHERE pc.posterminal_id = @posterminalId ORDER BY ca.article_id ASC, ca.category_id ASC `; +export const LIST_POS_CUSTOMER_GROUPS = ` +SELECT TOP (@limit) + cg.id, + cg.name, + CASE WHEN cg.id = co.poscustomergroup_id THEN '1' ELSE '0' END AS standard, + '0.000000' AS discountPercent, + DATEDIFF_BIG(second, '1970-01-01', cg.updated_at) AS lastChanged +FROM customergroup cg +INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = cg.company_id +INNER JOIN company co ON co.id = pt.company_id +WHERE cg.name <> 'Lieferanten' + AND DATEDIFF_BIG(second, '1970-01-01', cg.updated_at) > @cursor +ORDER BY DATEDIFF_BIG(second, '1970-01-01', cg.updated_at) ASC, cg.id ASC +`; + +export const LIST_POS_CUSTOMERS = ` +SELECT TOP (@limit) + e.id, + e.customergroup_id AS customergroupId, + e.first_name AS firstName, + e.name AS lastName, + e.[number] AS customerNumber, + ( + SELECT TOP 1 ea.street + FROM entityaddress ea + WHERE ea.entity_id = e.id + ORDER BY CASE WHEN ea.addresstype = 'billing' THEN 0 ELSE 1 END, ea.sort ASC, ea.id ASC + ) AS street, + ( + SELECT TOP 1 ea.streetnumber + FROM entityaddress ea + WHERE ea.entity_id = e.id + ORDER BY CASE WHEN ea.addresstype = 'billing' THEN 0 ELSE 1 END, ea.sort ASC, ea.id ASC + ) AS streetNumber, + ( + SELECT TOP 1 ea.city + FROM entityaddress ea + WHERE ea.entity_id = e.id + ORDER BY CASE WHEN ea.addresstype = 'billing' THEN 0 ELSE 1 END, ea.sort ASC, ea.id ASC + ) AS city, + ( + SELECT TOP 1 ea.zip + FROM entityaddress ea + WHERE ea.entity_id = e.id + ORDER BY CASE WHEN ea.addresstype = 'billing' THEN 0 ELSE 1 END, ea.sort ASC, ea.id ASC + ) AS postalCode, + ( + SELECT TOP 1 ea.county + FROM entityaddress ea + WHERE ea.entity_id = e.id + ORDER BY CASE WHEN ea.addresstype = 'billing' THEN 0 ELSE 1 END, ea.sort ASC, ea.id ASC + ) AS [state], + ( + SELECT TOP 1 ec.contact + FROM entitycontact ec + WHERE ec.entity_id = e.id AND ec.contacttype IN ('phone', 'mobile', 'tel') + ORDER BY ec.sort ASC, ec.id ASC + ) AS phone, + ( + SELECT TOP 1 ec.contact + FROM entitycontact ec + WHERE ec.entity_id = e.id AND ec.contacttype IN ('email', 'mail') + ORDER BY ec.sort ASC, ec.id ASC + ) AS email, + DATEDIFF_BIG(second, '1970-01-01', e.updated_at) AS lastChanged +FROM entity e +INNER JOIN customergroup cg ON cg.id = e.customergroup_id +INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = cg.company_id +WHERE cg.name <> 'Lieferanten' + AND DATEDIFF_BIG(second, '1970-01-01', e.updated_at) > @cursor +ORDER BY DATEDIFF_BIG(second, '1970-01-01', e.updated_at) ASC, e.id ASC +`; + + export const LIST_POS_CUSTOMER_GROUP_IDS = ` SELECT cg.id FROM customergroup cg @@ -395,6 +470,7 @@ WHERE cg.name <> 'Lieferanten' ORDER BY cg.id ASC `; + export const LIST_POS_PRODUCT_PRICES = ` SELECT pr.article_id AS articleId, diff --git a/src/providers/sqlite3/queries/posterminal.js b/src/providers/sqlite3/queries/posterminal.js index 4464daa..0491f2a 100644 --- a/src/providers/sqlite3/queries/posterminal.js +++ b/src/providers/sqlite3/queries/posterminal.js @@ -29,6 +29,88 @@ SELECT @posterminalId, id FROM cats WHERE 1 ON CONFLICT (posterminal_id, category_id) DO NOTHING `; +export const LIST_POS_CUSTOMER_GROUPS = ` +SELECT + cg.id, + cg.name, + CASE WHEN cg.id = co.poscustomergroup_id THEN '1' ELSE '0' END AS standard, + '0.000000' AS discountPercent, + CAST(strftime('%s', cg.updated_at) AS INTEGER) AS lastChanged +FROM customergroup cg +INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = cg.company_id +INNER JOIN company co ON co.id = pt.company_id +WHERE cg.name <> 'Lieferanten' + AND CAST(strftime('%s', cg.updated_at) AS INTEGER) > @cursor +ORDER BY lastChanged ASC, cg.id ASC +LIMIT @limit +`; + +export const LIST_POS_CUSTOMERS = ` +SELECT + e.id, + e.customergroup_id AS customergroupId, + e.first_name AS firstName, + e.name AS lastName, + e."number" AS customerNumber, + ( + SELECT ea.street + FROM entityaddress ea + WHERE ea.entity_id = e.id + ORDER BY CASE WHEN ea.addresstype = 'billing' THEN 0 ELSE 1 END, ea.sort ASC, ea.id ASC + LIMIT 1 + ) AS street, + ( + SELECT ea.streetnumber + FROM entityaddress ea + WHERE ea.entity_id = e.id + ORDER BY CASE WHEN ea.addresstype = 'billing' THEN 0 ELSE 1 END, ea.sort ASC, ea.id ASC + LIMIT 1 + ) AS streetNumber, + ( + SELECT ea.city + FROM entityaddress ea + WHERE ea.entity_id = e.id + ORDER BY CASE WHEN ea.addresstype = 'billing' THEN 0 ELSE 1 END, ea.sort ASC, ea.id ASC + LIMIT 1 + ) AS city, + ( + SELECT ea.zip + FROM entityaddress ea + WHERE ea.entity_id = e.id + ORDER BY CASE WHEN ea.addresstype = 'billing' THEN 0 ELSE 1 END, ea.sort ASC, ea.id ASC + LIMIT 1 + ) AS postalCode, + ( + SELECT ea.county + FROM entityaddress ea + WHERE ea.entity_id = e.id + ORDER BY CASE WHEN ea.addresstype = 'billing' THEN 0 ELSE 1 END, ea.sort ASC, ea.id ASC + LIMIT 1 + ) AS "state", + ( + SELECT ec.contact + FROM entitycontact ec + WHERE ec.entity_id = e.id AND ec.contacttype IN ('phone', 'mobile', 'tel') + ORDER BY ec.sort ASC, ec.id ASC + LIMIT 1 + ) AS phone, + ( + SELECT ec.contact + FROM entitycontact ec + WHERE ec.entity_id = e.id AND ec.contacttype IN ('email', 'mail') + ORDER BY ec.sort ASC, ec.id ASC + LIMIT 1 + ) AS email, + CAST(strftime('%s', e.updated_at) AS INTEGER) AS lastChanged +FROM entity e +INNER JOIN customergroup cg ON cg.id = e.customergroup_id +INNER JOIN posterminal pt ON pt.id = @posterminalId AND pt.company_id = cg.company_id +WHERE cg.name <> 'Lieferanten' + AND CAST(strftime('%s', e.updated_at) AS INTEGER) > @cursor +ORDER BY lastChanged ASC, e.id ASC +LIMIT @limit +`; + export const LIST_POS_CATEGORIES = ` SELECT c.id, diff --git a/src/store/posterminal/getCustomerGroupList.js b/src/store/posterminal/getCustomerGroupList.js new file mode 100644 index 0000000..caef445 --- /dev/null +++ b/src/store/posterminal/getCustomerGroupList.js @@ -0,0 +1,40 @@ +import { LIST_POS_CUSTOMER_GROUPS as MSSQL_SQL } from '../../providers/mssql/queries/posterminal.js'; +import { LIST_POS_CUSTOMER_GROUPS as SQLITE_SQL } from '../../providers/sqlite3/queries/posterminal.js'; +import makeRunner from '../runner.js'; + +function normalizeCursor(cursor) { + const n = Number(cursor) || 0; + if (n <= 0) return 0; + return n >= 1e11 ? Math.floor(n / 1000) : Math.floor(n); +} + +export default function getCustomerGroupList(provider) { + const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL; + + /** + * Lists customer groups for a POS terminal modified after the cursor, excluding 'Lieferanten'. + * + * @param {object} input + * @param {number} input.posterminalId - The POS terminal id. + * @param {number} [input.cursor=0] - Unix timestamp cursor. + * @param {number} [input.limit=50] - Max items to return. + * @param {object} [tx] - Optional transaction. + * @returns {Promise>} + */ + return async ({ posterminalId, cursor = 0, limit = 50 } = {}, tx) => { + const safeLimit = Number.isInteger(limit) && limit > 0 ? limit : 50; + const result = await makeRunner(provider, tx).query(sql, { + posterminalId: Number(posterminalId), + cursor: normalizeCursor(cursor), + limit: safeLimit, + }); + + return result.rows.map((row) => ({ + customerGroupId: String(row.id), + name: String(row.name ?? ''), + standard: String(row.standard ?? '0'), + discountPercent: String(row.discountPercent ?? '0.000000'), + lastChanged: String(row.lastChanged), + })); + }; +} diff --git a/src/store/posterminal/getCustomerList.js b/src/store/posterminal/getCustomerList.js new file mode 100644 index 0000000..3cb83e0 --- /dev/null +++ b/src/store/posterminal/getCustomerList.js @@ -0,0 +1,56 @@ +import { LIST_POS_CUSTOMERS as MSSQL_SQL } from '../../providers/mssql/queries/posterminal.js'; +import { LIST_POS_CUSTOMERS as SQLITE_SQL } from '../../providers/sqlite3/queries/posterminal.js'; +import makeRunner from '../runner.js'; + +function normalizeCursor(cursor) { + const n = Number(cursor) || 0; + if (n <= 0) return 0; + return n >= 1e11 ? Math.floor(n / 1000) : Math.floor(n); +} + +export default function getCustomerList(provider) { + const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL; + + /** + * Lists customers for a POS terminal modified after the cursor, excluding 'Lieferanten'. + * + * @param {object} input + * @param {number} input.posterminalId - The POS terminal id. + * @param {number} [input.cursor=0] - Unix timestamp cursor. + * @param {number} [input.limit=20] - Max items to return. + * @param {object} [tx] - Optional transaction. + * @returns {Promise>} + */ + return async ({ posterminalId, cursor = 0, limit = 20 } = {}, tx) => { + const safeLimit = Number.isInteger(limit) && limit > 0 ? limit : 20; + const result = await makeRunner(provider, tx).query(sql, { + posterminalId: Number(posterminalId), + cursor: normalizeCursor(cursor), + limit: safeLimit, + }); + + return result.rows.map((row) => ({ + id: String(row.id), + customerNumber: String(row.customerNumber ?? ''), + firstname: String(row.firstName ?? ''), + lastname: String(row.lastName ?? ''), + title: '', + company: '', + address: [row.street, row.streetNumber].filter(Boolean).join(' '), + addressSupplement: '', + city: String(row.city ?? ''), + postalCode: String(row.postalCode ?? ''), + state: String(row.state ?? ''), + country: 'DE', + phone: String(row.phone ?? ''), + email: String(row.email ?? ''), + customerGroupId: String(row.customergroupId ?? '1'), + salutation: '', + birthday: '', + discount: '0.00', + taxIdNumber: '', + lastChanged: String(row.lastChanged), + debtorNumber: '0', + })); + }; +}