u
This commit is contained in:
@@ -183,8 +183,10 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
|||||||
| [`routes/unit/delete.md`](routes/unit/delete.md) | `DELETE /unit` |
|
| [`routes/unit/delete.md`](routes/unit/delete.md) | `DELETE /unit` |
|
||||||
| [`routes/unit/list.md`](routes/unit/list.md) | `GET /unit` |
|
| [`routes/unit/list.md`](routes/unit/list.md) | `GET /unit` |
|
||||||
| [`routes/unit/upsert.md`](routes/unit/upsert.md) | `PUT /unit` |
|
| [`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/pos/client.md`](routes/pos/client.md) | `GET /v1/client` |
|
||||||
| [`routes/pos/init.md`](routes/pos/init.md) | `GET /v1/init` |
|
| [`routes/pos/init.md`](routes/pos/init.md) | `GET /v1/init` |
|
||||||
|
| [`routes/v1/product.md`](routes/v1/product.md) | `GET /v1/product` |
|
||||||
| [`routes/warehouse/list.md`](routes/warehouse/list.md) | `GET /warehouse` |
|
| [`routes/warehouse/list.md`](routes/warehouse/list.md) | `GET /warehouse` |
|
||||||
| [`routes/warehouse/create.md`](routes/warehouse/create.md) | `POST /warehouse` |
|
| [`routes/warehouse/create.md`](routes/warehouse/create.md) | `POST /warehouse` |
|
||||||
| [`routes/warehouse/order.md`](routes/warehouse/order.md) | `PUT /warehouse/order` |
|
| [`routes/warehouse/order.md`](routes/warehouse/order.md) | `PUT /warehouse/order` |
|
||||||
|
|||||||
@@ -13576,6 +13576,57 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/v1/product": {
|
||||||
|
"get": {
|
||||||
|
"summary": "JTL-POS product catalog synchronization",
|
||||||
|
"description": "Returns product catalog with prices, stock, variants, and image hashes modified after lastChangedProduct cursor.",
|
||||||
|
"tags": [
|
||||||
|
"POS Sync"
|
||||||
|
],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"BearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "lastChangedProduct",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Unix timestamp cursor of last product sync"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "limit",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"default": 50
|
||||||
|
},
|
||||||
|
"description": "Maximum number of products to return"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Array of product objects for JTL-POS",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/v1/init": {
|
"/v1/init": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
@@ -13841,6 +13892,57 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/v1/category": {
|
||||||
|
"get": {
|
||||||
|
"summary": "JTL-POS category synchronization",
|
||||||
|
"description": "Returns category hierarchy modified after lastChangedCategory cursor for the authenticated POS register.",
|
||||||
|
"tags": [
|
||||||
|
"POS Sync"
|
||||||
|
],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"BearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "lastChangedCategory",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Unix timestamp cursor of last category sync"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "limit",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"default": 50
|
||||||
|
},
|
||||||
|
"description": "Maximum number of categories to return"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Array of category objects for JTL-POS",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
|||||||
34
docs/api/routes/v1/category.md
Normal file
34
docs/api/routes/v1/category.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# `GET /v1/category`
|
||||||
|
|
||||||
|
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||||
|
|
||||||
|
JTL-POS category synchronization
|
||||||
|
|
||||||
|
Returns category hierarchy modified after lastChangedCategory cursor for the authenticated POS register.
|
||||||
|
|
||||||
|
## Query parameters
|
||||||
|
|
||||||
|
| Param | Required | Type | Description |
|
||||||
|
|-------|----------|------|-------------|
|
||||||
|
| `lastChangedCategory` | no | string | Unix timestamp cursor of last category sync |
|
||||||
|
| `limit` | no | integer | Maximum number of categories to return |
|
||||||
|
|
||||||
|
## Response `200`
|
||||||
|
|
||||||
|
Array of category objects for JTL-POS
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Errors
|
||||||
|
|
||||||
|
| Status | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| 401 | Unauthorized |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||||
34
docs/api/routes/v1/product.md
Normal file
34
docs/api/routes/v1/product.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# `GET /v1/product`
|
||||||
|
|
||||||
|
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||||
|
|
||||||
|
JTL-POS product catalog synchronization
|
||||||
|
|
||||||
|
Returns product catalog with prices, stock, variants, and image hashes modified after lastChangedProduct cursor.
|
||||||
|
|
||||||
|
## Query parameters
|
||||||
|
|
||||||
|
| Param | Required | Type | Description |
|
||||||
|
|-------|----------|------|-------------|
|
||||||
|
| `lastChangedProduct` | no | string | Unix timestamp cursor of last product sync |
|
||||||
|
| `limit` | no | integer | Maximum number of products to return |
|
||||||
|
|
||||||
|
## Response `200`
|
||||||
|
|
||||||
|
Array of product objects for JTL-POS
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Errors
|
||||||
|
|
||||||
|
| Status | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| 401 | Unauthorized |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||||
@@ -38,6 +38,13 @@ function emitStockEvents(companyId, body, result) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Array.isArray(result?.lines)) {
|
||||||
|
for (const line of result.lines) {
|
||||||
|
if (line?.sku) {
|
||||||
|
emit(`article-${line.sku}`, { companyId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -85,3 +85,13 @@ export async function getMaxOrderIdCount(params) {
|
|||||||
return store.posterminal.getMaxOrderIdCount(params);
|
return store.posterminal.getMaxOrderIdCount(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getCategoryList(params) {
|
||||||
|
const store = await getStore();
|
||||||
|
return store.posterminal.getCategoryList(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getProductList(params) {
|
||||||
|
const store = await getStore();
|
||||||
|
return store.posterminal.getProductList(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { Router } from 'express';
|
|||||||
import { posAuthMiddleware } from './middleware/posAuth.js';
|
import { posAuthMiddleware } from './middleware/posAuth.js';
|
||||||
import { handleClient } from './routes/client.js';
|
import { handleClient } from './routes/client.js';
|
||||||
import { handleInit } from './routes/init.js';
|
import { handleInit } from './routes/init.js';
|
||||||
|
import { handleCategory } from './routes/category.js';
|
||||||
|
import { handleProduct } from './routes/product.js';
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
@@ -11,5 +13,9 @@ router.get('/client', handleClient);
|
|||||||
// POS sync initialization counts
|
// POS sync initialization counts
|
||||||
router.get('/init', posAuthMiddleware, handleInit);
|
router.get('/init', posAuthMiddleware, handleInit);
|
||||||
|
|
||||||
|
// POS master data synchronization
|
||||||
|
router.get('/category', posAuthMiddleware, handleCategory);
|
||||||
|
router.get('/product', posAuthMiddleware, handleProduct);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
||||||
|
|||||||
67
src/v1/routes/category.js
Normal file
67
src/v1/routes/category.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { getCategoryList } from '../../db/posterminal.js';
|
||||||
|
|
||||||
|
function formatServerTimestamp() {
|
||||||
|
const d = new Date();
|
||||||
|
const pad = (n) => String(n).padStart(2, '0');
|
||||||
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /v1/category:
|
||||||
|
* get:
|
||||||
|
* summary: JTL-POS category synchronization
|
||||||
|
* description: Returns category hierarchy modified after lastChangedCategory cursor for the authenticated POS register.
|
||||||
|
* tags:
|
||||||
|
* - POS Sync
|
||||||
|
* security:
|
||||||
|
* - BearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: lastChangedCategory
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Unix timestamp cursor of last category sync
|
||||||
|
* - in: query
|
||||||
|
* name: limit
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* default: 50
|
||||||
|
* description: Maximum number of categories to return
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Array of category objects for JTL-POS
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* type: object
|
||||||
|
* 401:
|
||||||
|
* description: Unauthorized
|
||||||
|
*/
|
||||||
|
export async function handleCategory(req, res, next) {
|
||||||
|
try {
|
||||||
|
const posterminal = req.posterminal;
|
||||||
|
const cursor = Number(req.query.lastChangedCategory) || 0;
|
||||||
|
const limit = Number(req.query.limit) || 20;
|
||||||
|
|
||||||
|
const categories = await getCategoryList({
|
||||||
|
posterminalId: posterminal.id,
|
||||||
|
cursor,
|
||||||
|
limit,
|
||||||
|
});
|
||||||
|
|
||||||
|
const timestamp = formatServerTimestamp();
|
||||||
|
|
||||||
|
res.json(
|
||||||
|
categories.map((category) => ({
|
||||||
|
...category,
|
||||||
|
updated_at: timestamp,
|
||||||
|
created_at: timestamp,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
104
src/v1/routes/product.js
Normal file
104
src/v1/routes/product.js
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import { getProductList } from '../../db/posterminal.js';
|
||||||
|
|
||||||
|
const STATIC_DEFAULTS = {
|
||||||
|
sort: '0',
|
||||||
|
p_price: '0.00',
|
||||||
|
discountable: '0',
|
||||||
|
deposit: '0',
|
||||||
|
discount: '',
|
||||||
|
d_price: '0.0',
|
||||||
|
tax_rate2: '',
|
||||||
|
use_in_out_tax: '0',
|
||||||
|
barcode: null,
|
||||||
|
use_stock: '0',
|
||||||
|
q_div: '0',
|
||||||
|
quantity: '0',
|
||||||
|
unit: null,
|
||||||
|
single_bookable: '0',
|
||||||
|
annotation: '',
|
||||||
|
status: '0',
|
||||||
|
tags: '',
|
||||||
|
is_parent: '0',
|
||||||
|
parent: '0',
|
||||||
|
variants: '',
|
||||||
|
print_kitchen_receipt: '0',
|
||||||
|
deposit_name: '',
|
||||||
|
updated_at: '0001-01-01 00:00:00',
|
||||||
|
isCompositeProduct: '0',
|
||||||
|
attributes: [],
|
||||||
|
configurationGroups: '',
|
||||||
|
options: null,
|
||||||
|
hasBestBeforeDate: '0',
|
||||||
|
hasLotNumber: '0',
|
||||||
|
hasSerialNumber: '0',
|
||||||
|
PLU: '',
|
||||||
|
short_description: '',
|
||||||
|
minStock: '0',
|
||||||
|
container: [],
|
||||||
|
reservedQuantity: '0.00',
|
||||||
|
deliveryDetails: [],
|
||||||
|
isbn: '',
|
||||||
|
manufacturerName: null,
|
||||||
|
han: null,
|
||||||
|
productType: '0',
|
||||||
|
voucherData: null,
|
||||||
|
inputPrice: '0',
|
||||||
|
inputQuantity: '0',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /v1/product:
|
||||||
|
* get:
|
||||||
|
* summary: JTL-POS product catalog synchronization
|
||||||
|
* description: Returns product catalog with prices, stock, variants, and image hashes modified after lastChangedProduct cursor.
|
||||||
|
* tags:
|
||||||
|
* - POS Sync
|
||||||
|
* security:
|
||||||
|
* - BearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: lastChangedProduct
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Unix timestamp cursor of last product sync
|
||||||
|
* - in: query
|
||||||
|
* name: limit
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* default: 50
|
||||||
|
* description: Maximum number of products to return
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Array of product objects for JTL-POS
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* type: object
|
||||||
|
* 401:
|
||||||
|
* description: Unauthorized
|
||||||
|
*/
|
||||||
|
export async function handleProduct(req, res, next) {
|
||||||
|
try {
|
||||||
|
const posterminal = req.posterminal;
|
||||||
|
const cursor = Number(req.query.lastChangedProduct) || 0;
|
||||||
|
const limit = Number(req.query.limit) || 20;
|
||||||
|
|
||||||
|
const products = await getProductList({
|
||||||
|
posterminalId: posterminal.id,
|
||||||
|
cursor,
|
||||||
|
limit,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json(
|
||||||
|
products.map((product) => ({
|
||||||
|
...STATIC_DEFAULTS,
|
||||||
|
...product,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user