@alizadefaig/pos-server 1.2.26 → 1.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/core/Context.js +170 -0
- package/app/core/auth/index.js +133 -0
- package/app/core/auth/license.js +45 -0
- package/app/core/auth/posMode.js +260 -0
- package/app/core/auth/sanctum.js +209 -0
- package/app/core/auth/scope.js +231 -0
- package/app/core/emitter.js +67 -0
- package/app/core/errors.js +18 -0
- package/app/core/guard.js +54 -0
- package/app/core/idempotency.js +196 -0
- package/app/core/index.js +374 -0
- package/app/core/models/Order.js +176 -0
- package/app/core/models/OrderProduct.js +249 -0
- package/app/core/repositories/EventRepository.js +51 -0
- package/app/core/repositories/OrderProductRepository.js +225 -0
- package/app/core/repositories/OrderRepository.js +274 -0
- package/app/core/repositories/OutboxRepository.js +52 -0
- package/app/core/repositories/PaymentRepository.js +43 -0
- package/app/core/repositories/PrinterRepository.js +179 -0
- package/app/core/repositories/ProductRelations.js +148 -0
- package/app/core/repositories/SnapshotRepository.js +197 -0
- package/app/core/resources/HallResource.js +54 -0
- package/app/core/resources/OrderResource.js +177 -0
- package/app/core/resources/ProductResource.js +186 -0
- package/app/core/resources/ShiftResource.js +42 -0
- package/app/core/resources/TeamResource.js +85 -0
- package/app/core/resources/casts.js +55 -0
- package/app/core/services/AuthService.js +468 -0
- package/app/core/services/InitService.js +277 -0
- package/app/core/services/KdsService.js +639 -0
- package/app/core/services/OrderProductService.js +309 -0
- package/app/core/services/OrderService.js +903 -0
- package/app/core/services/PrintService.js +715 -0
- package/app/core/services/PrinterAdminService.js +324 -0
- package/app/core/services/ReportService.js +581 -0
- package/app/core/services/ShiftService.js +199 -0
- package/app/core/services/StorageService.js +425 -0
- package/app/core/services/TelegramService.js +162 -0
- package/app/core/support/db.js +48 -0
- package/app/core/support/ids.js +9 -0
- package/app/core/support/imageData.js +135 -0
- package/app/core/support/images.js +92 -0
- package/app/core/support/lanHandoff.js +105 -0
- package/app/core/support/lang.js +98 -0
- package/app/core/support/lock.js +63 -0
- package/app/core/support/num.js +51 -0
- package/app/core/support/php.js +125 -0
- package/app/core/support/pin.js +34 -0
- package/app/core/support/receipts.js +278 -0
- package/app/core/support/rows.js +38 -0
- package/app/core/support/str.js +31 -0
- package/app/core/support/teamSettings.js +77 -0
- package/app/core/support/telegram.js +253 -0
- package/app/core/support/telegramReport.js +143 -0
- package/app/core/support/time.js +58 -0
- package/app/core/support/tz.js +80 -0
- package/app/core/support/unlock.js +113 -0
- package/app/core/timers.js +151 -0
- package/app/db/Database.js +197 -1
- package/app/db/Migrator.js +45 -0
- package/app/db/driver.js +248 -0
- package/app/db/migrations/001_snapshot.sql +214 -0
- package/app/db/migrations/002_orders.sql +190 -0
- package/app/db/migrations/003_idempotency.sql +18 -0
- package/app/db/migrations/004_shifts.sql +21 -0
- package/app/db/migrations/005_printers.sql +43 -0
- package/app/db/migrations/006_sync.sql +136 -0
- package/app/db/migrations/007_printer_mac.sql +4 -0
- package/app/db/migrations/008_kds.sql +94 -0
- package/app/db/migrations/009_product_categories.sql +20 -0
- package/app/db/migrations/010_printers_sync.sql +43 -0
- package/app/db/migrations/011_team_logos.sql +13 -0
- package/app/db/migrations/012_category_workshop.sql +4 -0
- package/app/monitor.js +185 -0
- package/app/printers/address.js +348 -0
- package/app/proxy.js +11 -3
- package/app/relay/masters.js +173 -0
- package/app/security.js +218 -0
- package/app/socket/auth.js +160 -0
- package/app/socket/request.js +87 -0
- package/app/socket/server.js +121 -19
- package/app/sync/bridge.js +162 -0
- package/app/sync/cloud.js +120 -0
- package/app/sync/config.js +185 -0
- package/app/sync/discovery.js +546 -0
- package/app/sync/index.js +1644 -0
- package/app/sync/kv.js +26 -0
- package/app/sync/lan.js +139 -0
- package/app/sync/lanDevices.js +177 -0
- package/app/sync/lanFront.js +431 -0
- package/app/sync/mirror.js +236 -0
- package/app/sync/push.js +324 -0
- package/app/sync/reconcile.js +161 -0
- package/app/sync/signal.js +202 -0
- package/app/sync/snapshot.js +189 -0
- package/app/sync/store.js +234 -0
- package/app/tcp.js +11 -2
- package/package.json +6 -3
- package/routes/common/api/auth.js +38 -0
- package/routes/common/api/kds.js +37 -0
- package/routes/common/api/orderProducts.js +81 -0
- package/routes/common/api/orders.js +176 -0
- package/routes/common/api/printersCore.js +35 -0
- package/routes/common/api/reports.js +29 -0
- package/routes/common/socket.js +15 -35
- package/routes/common/tax.js +29 -7
- package/routes/desktop/api/offline.js +146 -0
- package/routes/desktop/api/printers.js +288 -5
- package/routes/desktop/local.js +130 -0
- package/routes/server/api/login.js +37 -0
- package/routes/server/api/platform.js +31 -0
- package/routes/server/api/shifts.js +25 -0
- package/routes/server/master.js +24 -0
- package/server.js +72 -3
- package/utils.js +6 -0
- package/tests/usbDiagnose.js +0 -59
- package/tests/usbPrinterTest.js +0 -20
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
const {Database} = require('../db/Database');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Настройки синка локального Node с облаком (OFFLINE-FIRST-PLAN §11, модель F).
|
|
5
|
+
*
|
|
6
|
+
* Читаются прямо из env, а не через app/core: ядро само спрашивает у синка текущий режим,
|
|
7
|
+
* и обратный require дал бы цикл.
|
|
8
|
+
*
|
|
9
|
+
* Всё выключено по умолчанию. Синк работает только поверх локальной SQLite: в облачном
|
|
10
|
+
* контуре (CORE_DB=pgsql) ядро пишет прямо в боевую базу, синхронизировать там нечего.
|
|
11
|
+
*/
|
|
12
|
+
const flag = (name, fallback = 'false') => (process.env[name] ?? fallback) === 'true';
|
|
13
|
+
|
|
14
|
+
const num = (name, fallback) => {
|
|
15
|
+
const value = Number(process.env[name]);
|
|
16
|
+
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const isCoreEnabled = () => flag('OFFLINE_CORE');
|
|
20
|
+
|
|
21
|
+
const isSyncEnabled = () => isCoreEnabled() && flag('OFFLINE_SYNC') && Database.defaultDialect() === 'sqlite';
|
|
22
|
+
|
|
23
|
+
const stripSlash = (value) => String(value || '').trim().replace(/\/+$/, '');
|
|
24
|
+
|
|
25
|
+
const masterSetting = () => stripSlash(process.env.OFFLINE_MASTER_URL);
|
|
26
|
+
|
|
27
|
+
/** OFFLINE_MASTER_URL=auto — адрес мастера ищется в сети (discovery.js). */
|
|
28
|
+
const isMasterAuto = () => masterSetting().toLowerCase() === 'auto';
|
|
29
|
+
|
|
30
|
+
// Последний найденный автопоиском адрес мастера; пишет только discovery.js.
|
|
31
|
+
let discoveredMasterUrl = null;
|
|
32
|
+
|
|
33
|
+
const setDiscoveredMasterUrl = (url) => {
|
|
34
|
+
discoveredMasterUrl = url ? stripSlash(url) : null;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Адрес мастера в зале (http://192.168.1.10:3005). При auto — найденный в сети, до первого
|
|
39
|
+
* ответа мастера null: запросы к мастеру тогда отвечают «мастер недоступен».
|
|
40
|
+
*/
|
|
41
|
+
const masterUrl = () => (isMasterAuto() ? discoveredMasterUrl : masterSetting() || null);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* standalone — одна касса: сама держит БД и сама синкается с облаком;
|
|
45
|
+
* master — то же, плюс обслуживает ведомые терминалы зала по LAN;
|
|
46
|
+
* follower — своей БД не ведёт: офлайн ходит к мастеру, синком не занимается.
|
|
47
|
+
*
|
|
48
|
+
* Ведомый — по настройке, а не по найденному адресу: касса с auto, ещё не нашедшая мастера,
|
|
49
|
+
* не должна на это время становиться самостоятельной и вести свои чеки.
|
|
50
|
+
*/
|
|
51
|
+
const role = () => {
|
|
52
|
+
if (masterSetting()) {
|
|
53
|
+
return 'follower';
|
|
54
|
+
}
|
|
55
|
+
return (process.env.OFFLINE_ROLE || '').toLowerCase() === 'master' ? 'master' : 'standalone';
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** Общий секрет зала: без него чужое устройство в той же сети не достучится до мастера. */
|
|
59
|
+
const lanKey = () => process.env.CAFEPOS_LAN_KEY || null;
|
|
60
|
+
|
|
61
|
+
const LAN_KEY_HEADER = 'x-cafepos-lan-key';
|
|
62
|
+
|
|
63
|
+
const intervals = () => ({
|
|
64
|
+
tick: num('OFFLINE_SYNC_TICK_MS', 3000),
|
|
65
|
+
health: num('OFFLINE_HEALTH_MS', 3000),
|
|
66
|
+
pull: num('OFFLINE_PULL_MS', 15000),
|
|
67
|
+
// сигнальный сокет облака оборван — патчи о чужих правках не придут, опрашиваем чаще
|
|
68
|
+
pullWithoutSignal: num('OFFLINE_PULL_NO_SIGNAL_MS', 3000),
|
|
69
|
+
snapshot: num('OFFLINE_SNAPSHOT_MS', 600000),
|
|
70
|
+
signalDebounce: num('OFFLINE_SIGNAL_DEBOUNCE_MS', 300),
|
|
71
|
+
// модель M: как часто спрашивать у облака режим заведения (заодно это heartbeat кассы)
|
|
72
|
+
modePoll: num('OFFLINE_MODE_POLL_MS', 10000),
|
|
73
|
+
// выход терминала при недосланном: столько push досылает очередь, прежде чем токен отзовут
|
|
74
|
+
logoutGrace: num('OFFLINE_LOGOUT_GRACE_MS', 600000),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const timeouts = () => ({
|
|
78
|
+
health: num('OFFLINE_HEALTH_TIMEOUT_MS', 3000),
|
|
79
|
+
api: num('OFFLINE_API_TIMEOUT_MS', 15000),
|
|
80
|
+
snapshot: num('OFFLINE_SNAPSHOT_TIMEOUT_MS', 60000),
|
|
81
|
+
push: num('OFFLINE_PUSH_TIMEOUT_MS', 30000),
|
|
82
|
+
// запрос ведомого к мастеру: мастер сам может ждать облако, поэтому запас больше api
|
|
83
|
+
master: num('OFFLINE_MASTER_TIMEOUT_MS', 20000),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const limits = () => ({
|
|
87
|
+
pushBatch: num('OFFLINE_PUSH_BATCH', 50),
|
|
88
|
+
pullLimit: num('OFFLINE_PULL_LIMIT', 500),
|
|
89
|
+
pullPages: num('OFFLINE_PULL_PAGES', 20),
|
|
90
|
+
// гистерезис связи: сколько подряд провалов/успехов переключают режим
|
|
91
|
+
failuresToOffline: num('OFFLINE_FAILURES_TO_OFFLINE', 2),
|
|
92
|
+
successesToOnline: num('OFFLINE_SUCCESSES_TO_ONLINE', 3),
|
|
93
|
+
// чек, который облако раз за разом не принимает, не должен вечно держать recovering
|
|
94
|
+
poisonAttempts: num('OFFLINE_POISON_ATTEMPTS', 5),
|
|
95
|
+
// сколько дней локально держим закрытые чеки (архив офлайн)
|
|
96
|
+
keepClosedDays: num('OFFLINE_KEEP_CLOSED_DAYS', 3),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Сверка касса ↔ облако (P2): закрытые чеки за последние windowHours часов, раз в interval.
|
|
101
|
+
* settle — хвост окна, который не сверяется: только что закрытый чек мог ещё не доехать.
|
|
102
|
+
* Включена по умолчанию, но работает только внутри синка (сам синк за флагами).
|
|
103
|
+
*/
|
|
104
|
+
const isReconcileEnabled = () => flag('OFFLINE_RECONCILE', 'true');
|
|
105
|
+
|
|
106
|
+
const reconcile = () => ({
|
|
107
|
+
interval: num('OFFLINE_RECONCILE_MS', 300000),
|
|
108
|
+
// после расхождения — проверить лечение раньше обычного
|
|
109
|
+
retry: num('OFFLINE_RECONCILE_RETRY_MS', 60000),
|
|
110
|
+
windowHours: num('OFFLINE_RECONCILE_WINDOW_H', 24),
|
|
111
|
+
settle: num('OFFLINE_RECONCILE_SETTLE_MS', 300000),
|
|
112
|
+
maxHeal: num('OFFLINE_RECONCILE_MAX_HEAL', 500),
|
|
113
|
+
// столько сверок подряд с расхождением — тревога в суперадминке
|
|
114
|
+
alarmAfter: num('OFFLINE_RECONCILE_ALARM_AFTER', 3),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Облачный Node (модель M): принимает сигнальные сокеты мастер-касс и ретранслирует им события
|
|
119
|
+
* заведений в режиме local (POST /master/request от Laravel). Выключено по умолчанию.
|
|
120
|
+
*/
|
|
121
|
+
const isMasterRelayEnabled = () => flag('MASTER_RELAY_ENABLED');
|
|
122
|
+
|
|
123
|
+
// Меньше таймаутов Laravel (pos_mode.relay_timeout 20с / relay_print_timeout 150с): облачный Node
|
|
124
|
+
// обязан ответить сам — «мастер не успел», а не оборвать Laravel на полуслове.
|
|
125
|
+
const relayTimeouts = () => ({
|
|
126
|
+
api: num('MASTER_RELAY_TIMEOUT_MS', 17000),
|
|
127
|
+
print: num('MASTER_RELAY_PRINT_TIMEOUT_MS', 140000),
|
|
128
|
+
// проверка личности мастера через Laravel (sync.mode)
|
|
129
|
+
verify: num('MASTER_RELAY_VERIFY_TIMEOUT_MS', 10000),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
/** Общий секрет Laravel ↔ Node для служебных путей (/socket, /socket/request, /master/*). */
|
|
133
|
+
const internalKey = () => process.env.INTERNAL_API_KEY || null;
|
|
134
|
+
|
|
135
|
+
const INTERNAL_KEY_HEADER = 'x-internal-key';
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Переход браузера облако → мастер по LAN (официант на телефоне без интернета). Мастер раздаёт
|
|
139
|
+
* копию фронта с облака и пускает телефон по его токену (список хешей токенов заведения — из
|
|
140
|
+
* облака, sync.lanDevices). Только у мастера зала с ключом: остальным раздавать некого.
|
|
141
|
+
*/
|
|
142
|
+
const isLanFrontEnabled = () => flag('LAN_FRONT') && isSyncEnabled() && role() === 'master' && Boolean(lanKey());
|
|
143
|
+
|
|
144
|
+
/** Откуда брать фронт: тот же сайт, с которого работает официант. */
|
|
145
|
+
const lanFrontUrl = () => stripSlash(process.env.LAN_FRONT_URL) || 'https://platform.cafepos.az';
|
|
146
|
+
|
|
147
|
+
const lanFront = () => ({
|
|
148
|
+
// как часто сверять версию фронта с облаком
|
|
149
|
+
sync: num('LAN_FRONT_SYNC_MS', 600000),
|
|
150
|
+
// повтор после неудачной загрузки
|
|
151
|
+
retry: num('LAN_FRONT_RETRY_MS', 60000),
|
|
152
|
+
// как часто обновлять список токенов устройств
|
|
153
|
+
devices: num('LAN_DEVICES_MS', 60000),
|
|
154
|
+
timeout: num('LAN_FRONT_TIMEOUT_MS', 30000),
|
|
155
|
+
maxFiles: num('LAN_FRONT_MAX_FILES', 2000),
|
|
156
|
+
maxBytes: num('LAN_FRONT_MAX_MB', 150) * 1024 * 1024,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/** Путь проверки связи. /up — health-роут Laravel 11: через облачный Node он проверяет весь путь. */
|
|
160
|
+
const healthPath = () => process.env.OFFLINE_HEALTH_PATH || '/up';
|
|
161
|
+
|
|
162
|
+
module.exports = {
|
|
163
|
+
isCoreEnabled,
|
|
164
|
+
isSyncEnabled,
|
|
165
|
+
masterUrl,
|
|
166
|
+
isMasterAuto,
|
|
167
|
+
setDiscoveredMasterUrl,
|
|
168
|
+
role,
|
|
169
|
+
lanKey,
|
|
170
|
+
LAN_KEY_HEADER,
|
|
171
|
+
intervals,
|
|
172
|
+
timeouts,
|
|
173
|
+
limits,
|
|
174
|
+
isReconcileEnabled,
|
|
175
|
+
reconcile,
|
|
176
|
+
healthPath,
|
|
177
|
+
stripSlash,
|
|
178
|
+
isMasterRelayEnabled,
|
|
179
|
+
relayTimeouts,
|
|
180
|
+
internalKey,
|
|
181
|
+
INTERNAL_KEY_HEADER,
|
|
182
|
+
isLanFrontEnabled,
|
|
183
|
+
lanFrontUrl,
|
|
184
|
+
lanFront,
|
|
185
|
+
};
|