import * as db from '../../db/posterminal.js'; import { emit } from '../../api/sse.js'; /** * @openapi * /v1/init: * get: * tags: [POS] * summary: POS sync initialization counts * description: | * Returns entity change counts since the provided `lastChanged*` sync queue ID cursors * (`posterminalsyncqueue.id` / `posterminalobituary.id`) for the authenticated POS terminal * (`Authorization: Bearer `). * x-markdown: pos/init.md * parameters: * - in: header * name: Authorization * required: true * schema: * type: string * description: POS device authToken obtained during pairing (`Bearer ` or ``) * example: "Bearer c30099b66ec1fcb9ccd05795423c94e8" * - in: header * name: version * required: false * schema: * type: string * description: POS client software version reported by the device * example: "2.0.0.5" * - in: query * name: lastChangedProduct * required: false * schema: * type: integer * default: 0 * description: Sequential ID cursor of last synced product entry (`posterminalsyncqueue.id`) * example: 0 * - in: query * name: lastChangedCategory * required: false * schema: * type: integer * default: 0 * description: Sequential ID cursor of last synced category entry (`posterminalsyncqueue.id`) * example: 0 * - in: query * name: lastChangedCustomer * required: false * schema: * type: integer * default: 0 * description: Sequential ID cursor of last synced customer entry (`posterminalsyncqueue.id`) * example: 0 * - in: query * name: lastChangedCustomerGroup * required: false * schema: * type: integer * default: 0 * description: Sequential ID cursor of last synced customer group entry (`posterminalsyncqueue.id`) * example: 0 * - in: query * name: lastChangedCompositeProduct * required: false * schema: * type: integer * default: 0 * description: Sequential ID cursor of last synced composite product entry (`posterminalsyncqueue.id`) * example: 0 * - in: query * name: lastChangedDeletedEntity * required: false * schema: * type: integer * default: 0 * description: Sequential ID cursor of last synced deleted entity (`posterminalobituary.id`) * example: 0 * responses: * 200: * description: Sync initialization counts * content: * application/json: * schema: * type: object * properties: * version: * type: string * example: "1.10.12.0" * product_count: * type: string * example: "19" * category_count: * type: string * example: "4" * customer_count: * type: string * example: "0" * customerGroup_count: * type: string * example: "1" * compositeProduct_count: * type: string * example: "0" * configurationGroup_count: * type: string * example: "0" * configurationItem_count: * type: string * example: "0" * deletedEntity_count: * type: string * example: "0" * max_orderId_count: * type: string * example: "0" * 401: * description: Missing or invalid POS Authorization token * content: * application/json: * schema: * type: object * properties: * Message: * type: string * example: "Authorization has been denied for this request." * @param {import('express').Request} req * @param {import('express').Response} res */ export async function handleInit(req, res) { const posterminalId = req.posterminal.id; const rawVersion = req.headers.version || req.headers.clientversion; const incomingVersion = rawVersion ? String(rawVersion).trim() : ''; const currentVersion = req.posterminal.clientversion ? String(req.posterminal.clientversion).trim() : ''; const updateVersionPromise = (incomingVersion && incomingVersion !== currentVersion) ? db.setClientversion(posterminalId, incomingVersion) .then(() => { req.posterminal.clientversion = incomingVersion; if (req.posterminal.companyId) { emit('posterminal', { companyId: req.posterminal.companyId }); } }) .catch((err) => { console.error(`Failed to update posterminal ${posterminalId} version:`, err); }) : null; const productCursor = Number(req.query.lastChangedProduct) || 0; const categoryCursor = Number(req.query.lastChangedCategory) || 0; const customerCursor = Number(req.query.lastChangedCustomer) || 0; const customerGroupCursor = Number(req.query.lastChangedCustomerGroup) || 0; const compositeProductCursor = Number(req.query.lastChangedCompositeProduct) || 0; const deletedEntityCursor = Number(req.query.lastChangedDeletedEntity) || 0; try { const [ productCount, categoryCount, customerCount, customerGroupCount, compositeProductCount, deletedEntityCount, maxOrderIdCount, ] = await Promise.all([ db.getProductCount({ posterminalId, cursor: productCursor }), db.getCategoryCount({ posterminalId, cursor: categoryCursor }), db.getCustomerCount({ posterminalId, cursor: customerCursor }), db.getCustomerGroupCount({ posterminalId, cursor: customerGroupCursor }), db.getCompositeProductCount({ posterminalId, cursor: compositeProductCursor }), db.getDeletedEntityCount({ posterminalId, cursor: deletedEntityCursor }), db.getMaxOrderIdCount({ posterminalId }), updateVersionPromise, ]); return res.status(200).json({ version: '1.10.12.0', product_count: String(productCount), category_count: String(categoryCount), customer_count: String(customerCount), customerGroup_count: String(customerGroupCount), compositeProduct_count: String(compositeProductCount), configurationGroup_count: '0', configurationItem_count: '0', deletedEntity_count: String(deletedEntityCount), max_orderId_count: String(maxOrderIdCount), }); } catch (err) { console.error('POS /v1/init error:', err); return res.status(500).json({ Message: 'Internal server error' }); } }