vv-iiko-pp-parser 1.0.6
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/CHANGELOG.md +151 -0
- package/README.md +582 -0
- package/dist/clients/clients.fetcher.d.ts +102 -0
- package/dist/clients/clients.fetcher.d.ts.map +1 -0
- package/dist/clients/clients.fetcher.js +196 -0
- package/dist/clients/clients.fetcher.js.map +1 -0
- package/dist/clients/clients.parser.d.ts +144 -0
- package/dist/clients/clients.parser.d.ts.map +1 -0
- package/dist/clients/clients.parser.js +473 -0
- package/dist/clients/clients.parser.js.map +1 -0
- package/dist/clients/clients.service.d.ts +90 -0
- package/dist/clients/clients.service.d.ts.map +1 -0
- package/dist/clients/clients.service.js +277 -0
- package/dist/clients/clients.service.js.map +1 -0
- package/dist/clients/clients.types.d.ts +127 -0
- package/dist/clients/clients.types.d.ts.map +1 -0
- package/dist/clients/clients.types.js +6 -0
- package/dist/clients/clients.types.js.map +1 -0
- package/dist/clients/index.d.ts +5 -0
- package/dist/clients/index.d.ts.map +1 -0
- package/dist/clients/index.js +25 -0
- package/dist/clients/index.js.map +1 -0
- package/dist/core/auth/iiko-auth.service.d.ts +52 -0
- package/dist/core/auth/iiko-auth.service.d.ts.map +1 -0
- package/dist/core/auth/iiko-auth.service.js +302 -0
- package/dist/core/auth/iiko-auth.service.js.map +1 -0
- package/dist/core/http/iiko-http.client.d.ts +13 -0
- package/dist/core/http/iiko-http.client.d.ts.map +1 -0
- package/dist/core/http/iiko-http.client.js +55 -0
- package/dist/core/http/iiko-http.client.js.map +1 -0
- package/dist/core/iiko-parser.config.d.ts +28 -0
- package/dist/core/iiko-parser.config.d.ts.map +1 -0
- package/dist/core/iiko-parser.config.js +76 -0
- package/dist/core/iiko-parser.config.js.map +1 -0
- package/dist/core/parser/iiko-parser.service.d.ts +15 -0
- package/dist/core/parser/iiko-parser.service.d.ts.map +1 -0
- package/dist/core/parser/iiko-parser.service.js +156 -0
- package/dist/core/parser/iiko-parser.service.js.map +1 -0
- package/dist/core/session/iiko-session.service.d.ts +68 -0
- package/dist/core/session/iiko-session.service.d.ts.map +1 -0
- package/dist/core/session/iiko-session.service.js +209 -0
- package/dist/core/session/iiko-session.service.js.map +1 -0
- package/dist/iiko-parser.d.ts +149 -0
- package/dist/iiko-parser.d.ts.map +1 -0
- package/dist/iiko-parser.js +209 -0
- package/dist/iiko-parser.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/company-profile.interface.d.ts +12 -0
- package/dist/interfaces/company-profile.interface.d.ts.map +1 -0
- package/dist/interfaces/company-profile.interface.js +3 -0
- package/dist/interfaces/company-profile.interface.js.map +1 -0
- package/dist/invoices/index.d.ts +6 -0
- package/dist/invoices/index.d.ts.map +1 -0
- package/dist/invoices/index.js +22 -0
- package/dist/invoices/index.js.map +1 -0
- package/dist/invoices/invoices.fetcher.d.ts +49 -0
- package/dist/invoices/invoices.fetcher.d.ts.map +1 -0
- package/dist/invoices/invoices.fetcher.js +141 -0
- package/dist/invoices/invoices.fetcher.js.map +1 -0
- package/dist/invoices/invoices.filters.d.ts +40 -0
- package/dist/invoices/invoices.filters.d.ts.map +1 -0
- package/dist/invoices/invoices.filters.js +81 -0
- package/dist/invoices/invoices.filters.js.map +1 -0
- package/dist/invoices/invoices.parser.d.ts +101 -0
- package/dist/invoices/invoices.parser.d.ts.map +1 -0
- package/dist/invoices/invoices.parser.js +540 -0
- package/dist/invoices/invoices.parser.js.map +1 -0
- package/dist/invoices/invoices.service.d.ts +82 -0
- package/dist/invoices/invoices.service.d.ts.map +1 -0
- package/dist/invoices/invoices.service.js +361 -0
- package/dist/invoices/invoices.service.js.map +1 -0
- package/dist/invoices/invoices.storage.service.d.ts +30 -0
- package/dist/invoices/invoices.storage.service.d.ts.map +1 -0
- package/dist/invoices/invoices.storage.service.js +135 -0
- package/dist/invoices/invoices.storage.service.js.map +1 -0
- package/dist/invoices/invoices.types.d.ts +94 -0
- package/dist/invoices/invoices.types.d.ts.map +1 -0
- package/dist/invoices/invoices.types.js +3 -0
- package/dist/invoices/invoices.types.js.map +1 -0
- package/dist/types.d.ts +138 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
# vv-iiko-pp-parser
|
|
2
|
+
|
|
3
|
+
🇺🇿 **Unofficial SDK for iiko Partner Portal API** — Node.js клиент для получения данных инвойсов из партнерского портала iiko.
|
|
4
|
+
|
|
5
|
+
> ⚠️ **Важно:** Это частный пакет с ограниченным доступом. Для установки требуется авторизация в npm.
|
|
6
|
+
|
|
7
|
+
## 📋 Что это?
|
|
8
|
+
|
|
9
|
+
Этот пакет предоставляет простой API для работы с закрытым веб-интерфейсом [iiko Partner Portal](https://pp.iiko.uz), позволяя автоматизировать получение:
|
|
10
|
+
|
|
11
|
+
- 📄 **Инвойсов** с детальной информацией
|
|
12
|
+
- 🏢 **Данных компании** и профиля
|
|
13
|
+
- 🔍 **Фильтрации** по различным критериям
|
|
14
|
+
|
|
15
|
+
## 🚀 Установка
|
|
16
|
+
|
|
17
|
+
### Авторизация в npm
|
|
18
|
+
|
|
19
|
+
Перед установкой необходимо авторизоваться в npm:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm login
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Установка пакета
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @mirzaev/vv-iiko-pp-parser
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## ⚙️ Конфигурация
|
|
32
|
+
|
|
33
|
+
Создайте `.env` файл с вашими учетными данными:
|
|
34
|
+
|
|
35
|
+
```env
|
|
36
|
+
IIKO_PP_LOGIN=your_username
|
|
37
|
+
IIKO_PP_PASSWORD=your_password
|
|
38
|
+
|
|
39
|
+
# Опционально: пользовательский путь для хранения cookies
|
|
40
|
+
# По умолчанию используется: {projectRoot}/.vv-cookies
|
|
41
|
+
# VV_IIKO_COOKIES_DIR=/custom/path/to/cookies
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 📂 Хранение cookies
|
|
45
|
+
|
|
46
|
+
Cookies сохраняются автоматически после авторизации для переиспользования между запусками.
|
|
47
|
+
|
|
48
|
+
**Расположение по умолчанию:** `.vv-cookies/` в корне вашего проекта
|
|
49
|
+
|
|
50
|
+
**Пользовательский путь:**
|
|
51
|
+
```typescript
|
|
52
|
+
const parser = new IikoParser({
|
|
53
|
+
login: process.env.IIKO_PP_LOGIN,
|
|
54
|
+
password: process.env.IIKO_PP_PASSWORD,
|
|
55
|
+
cookiesPath: '/custom/path/iiko.cookies.json' // Абсолютный путь к файлу
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Или через переменную окружения:
|
|
60
|
+
```env
|
|
61
|
+
VV_IIKO_COOKIES_DIR=/custom/path/to/cookies
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 🎯 Быстрый старт
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { IikoParser } from '@mirzaev/vv-iiko-pp-parser';
|
|
68
|
+
import 'dotenv/config';
|
|
69
|
+
|
|
70
|
+
const parser = new IikoParser({
|
|
71
|
+
baseUrl: 'https://pp.iiko.uz',
|
|
72
|
+
language: 'en',
|
|
73
|
+
login: process.env.IIKO_PP_LOGIN,
|
|
74
|
+
password: process.env.IIKO_PP_PASSWORD
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Инициализация сессии
|
|
78
|
+
await parser.ensureSession();
|
|
79
|
+
|
|
80
|
+
// Получение всех инвойсов за январь 2026
|
|
81
|
+
const invoices = await parser.getInvoices({
|
|
82
|
+
dateFrom: '2026-01-01',
|
|
83
|
+
dateTo: '2026-01-31'
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
console.log(`Найдено ${invoices.length} инвойсов`);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## 🔍 Фильтрация данных
|
|
90
|
+
|
|
91
|
+
### По периоду времени
|
|
92
|
+
|
|
93
|
+
Фильтрация по датам выполняется через параметры `dateFrom` и `dateTo` в формате `YYYY-MM-DD`:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
const invoices = await parser.getInvoices({
|
|
97
|
+
dateFrom: '2026-01-01', // С какой даты
|
|
98
|
+
dateTo: '2026-01-31' // До какой даты (включительно)
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
> 📝 **Формат дат**: `YYYY-MM-DD` (например, `2026-01-15`)
|
|
103
|
+
> API iiko автоматически конвертирует в формат `dd.mm.yyyy`
|
|
104
|
+
|
|
105
|
+
### Загрузка деталей из модального окна
|
|
106
|
+
|
|
107
|
+
По умолчанию `items` и `subscriptions` остаются пустыми массивами. Чтобы загрузить детали из модальных окон, используйте флаг `withDetails`:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
const invoices = await parser.getInvoices({
|
|
111
|
+
withDetails: true // 🔥 Загрузит items и subscriptions для каждого инвойса
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Теперь у каждого инвойса заполнены:
|
|
115
|
+
console.log(invoices[0].items); // [{ productName, price, quantity, discount, amount }]
|
|
116
|
+
console.log(invoices[0].subscriptions); // [{ productName, quantity, price, amount }]
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
⚠️ **Важно**: Загрузка деталей выполняется последовательно для каждого инвойса, это может занять время при большом количестве инвойсов.
|
|
120
|
+
|
|
121
|
+
### По tax_id компании
|
|
122
|
+
|
|
123
|
+
> ⚠️ **Важно**: Используйте формат с пробелами как в системе!
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
const invoices = await parser.getInvoices({
|
|
127
|
+
dateFrom: '2026-01-01',
|
|
128
|
+
dateTo: '2026-01-31',
|
|
129
|
+
searchBy: 'tax_id',
|
|
130
|
+
searchValue: '305 845 090' // ← Формат с пробелами!
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### По номеру инвойса
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const invoice = await parser.getInvoices({
|
|
138
|
+
dateFrom: '2025-01-01',
|
|
139
|
+
dateTo: '2026-01-31',
|
|
140
|
+
searchBy: 'invoice_number',
|
|
141
|
+
searchValue: 'INV3816690'
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### По имени клиента
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const invoices = await parser.getInvoices({
|
|
149
|
+
dateFrom: '2025-01-01',
|
|
150
|
+
dateTo: '2026-01-31',
|
|
151
|
+
searchBy: 'client',
|
|
152
|
+
searchValue: 'KURANT'
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### По имени фирмы
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
const invoices = await parser.getInvoices({
|
|
160
|
+
dateFrom: '2025-01-01',
|
|
161
|
+
dateTo: '2026-01-31',
|
|
162
|
+
searchBy: 'firm',
|
|
163
|
+
searchValue: 'VEDA VECTOR'
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## � Пагинация
|
|
168
|
+
|
|
169
|
+
По умолчанию загружаются **все страницы** инвойсов автоматически.
|
|
170
|
+
|
|
171
|
+
Вы можете управлять пагинацией:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// Ограничить количество страниц
|
|
175
|
+
const invoices = await parser.getInvoices({
|
|
176
|
+
pagination: {
|
|
177
|
+
maxPages: 2 // Загрузить только первые 2 страницы
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// Изменить размер страницы
|
|
184
|
+
const invoices = await parser.getInvoices({
|
|
185
|
+
pagination: {
|
|
186
|
+
pageSize: 100, // 100 инвойсов на страницу (по умолчанию: 50)
|
|
187
|
+
maxPages: 5 // Максимум 5 страниц
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Без ограничений (поведение по умолчанию)
|
|
194
|
+
const invoices = await parser.getInvoices();
|
|
195
|
+
// Загрузит все страницы до пустой
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
⚠️ **Примечание:** Пагинация останавливается автоматически при достижении пустой страницы, даже если лимит `maxPages` не достигнут.
|
|
199
|
+
|
|
200
|
+
## �📊 Структура данных
|
|
201
|
+
|
|
202
|
+
### InvoiceData
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
interface InvoiceData {
|
|
206
|
+
invoiceNumber: string; // Номер инвойса (например: "INV3816690")
|
|
207
|
+
invoiceDate: string; // Дата инвойса
|
|
208
|
+
dueDate: string; // Срок оплаты
|
|
209
|
+
clientName: string; // Название клиента
|
|
210
|
+
companyName: string; // Название компании
|
|
211
|
+
taxId: string; // Tax ID (только цифры)
|
|
212
|
+
status: string; // Статус (Issued, Paid, Cancelled)
|
|
213
|
+
amount: number; // Общая сумма (число)
|
|
214
|
+
detailsUrl: string; // URL для загрузки деталей из модального окна
|
|
215
|
+
items: InvoiceItem[]; // Элементы инвойса (заполняются при withDetails: true)
|
|
216
|
+
subscriptions: Subscription[]; // Подписки (заполняются при withDetails: true)
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### InvoiceItem
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
interface InvoiceItem {
|
|
224
|
+
productName: string; // Название продукта
|
|
225
|
+
price: number; // Цена
|
|
226
|
+
quantity: number; // Количество
|
|
227
|
+
discount: number; // Скидка (%)
|
|
228
|
+
amount: number; // Сумма
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Subscription
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
interface Subscription {
|
|
236
|
+
productName: string; // Название продукта
|
|
237
|
+
quantity: number; // Количество
|
|
238
|
+
price: number; // Цена
|
|
239
|
+
amount: number; // Сумма
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### CompanyProfile
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
interface CompanyProfile {
|
|
247
|
+
name: string; // Название компании
|
|
248
|
+
phone: string; // Телефон
|
|
249
|
+
email: string; // Email
|
|
250
|
+
address: string; // Адрес
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### ClientData
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
interface ClientData {
|
|
258
|
+
uuid: string; // UUID клиента (формат: XXX-XXX-XXX)
|
|
259
|
+
name: string; // Название клиента
|
|
260
|
+
clientId: string; // ID клиента в системе
|
|
261
|
+
iikoVersion?: string; // Версия iiko (например: "9.2.6029")
|
|
262
|
+
email?: string; // Email клиента
|
|
263
|
+
phone?: string; // Телефон клиента
|
|
264
|
+
address?: string; // Адрес клиента
|
|
265
|
+
legalEntity?: string; // Юридическое лицо
|
|
266
|
+
tin?: string; // ИНН (только цифры)
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### ClientsFilter
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
interface ClientsFilter {
|
|
274
|
+
query?: string; // Поиск по названию или UID
|
|
275
|
+
perPage?: number; // Количество клиентов на странице (по умолчанию: 20)
|
|
276
|
+
maxPages?: number; // Максимальное количество страниц (по умолчанию: все)
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### InvoicesFilter
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
interface InvoicesFilter {
|
|
284
|
+
dateFrom?: string; // Дата начала (YYYY-MM-DD)
|
|
285
|
+
dateTo?: string; // Дата окончания (YYYY-MM-DD)
|
|
286
|
+
searchBy?: 'client' | 'firm' | 'tax_id' | 'invoice_number';
|
|
287
|
+
searchValue?: string; // Значение для поиска
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## 👥 Получение списка клиентов
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// Получить всех клиентов с полной информацией
|
|
295
|
+
const allClients = await parser.getClients();
|
|
296
|
+
|
|
297
|
+
console.log(`Найдено ${allClients.length} клиентов`);
|
|
298
|
+
|
|
299
|
+
// Вывести информацию о первом клиенте
|
|
300
|
+
const client = allClients[0];
|
|
301
|
+
console.log({
|
|
302
|
+
name: client.name,
|
|
303
|
+
uuid: client.uuid,
|
|
304
|
+
iikoVersion: client.iikoVersion,
|
|
305
|
+
email: client.email,
|
|
306
|
+
phone: client.phone,
|
|
307
|
+
address: client.address,
|
|
308
|
+
legalEntity: client.legalEntity,
|
|
309
|
+
tin: client.tin
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Фильтрация клиентов
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
// Поиск по названию
|
|
317
|
+
const restaurantClients = await parser.getClients({
|
|
318
|
+
query: 'Restaurant'
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// Поиск по UUID
|
|
322
|
+
const specificClient = await parser.getClients({
|
|
323
|
+
query: '212-191-451'
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// Ограничение пагинации
|
|
327
|
+
const firstPage = await parser.getClients({
|
|
328
|
+
perPage: 20,
|
|
329
|
+
maxPages: 1
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// Загрузить больше клиентов за раз
|
|
333
|
+
const manyClients = await parser.getClients({
|
|
334
|
+
perPage: 50,
|
|
335
|
+
maxPages: 5
|
|
336
|
+
});
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Обработка данных клиентов
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
const clients = await parser.getClients();
|
|
343
|
+
|
|
344
|
+
// Фильтрация клиентов с email
|
|
345
|
+
const clientsWithEmail = clients.filter(c => c.email);
|
|
346
|
+
|
|
347
|
+
// Группировка по версии iiko
|
|
348
|
+
const byVersion = clients.reduce((acc, client) => {
|
|
349
|
+
const version = client.iikoVersion || 'Unknown';
|
|
350
|
+
if (!acc[version]) acc[version] = [];
|
|
351
|
+
acc[version].push(client);
|
|
352
|
+
return acc;
|
|
353
|
+
}, {});
|
|
354
|
+
|
|
355
|
+
// Клиенты без ИНН
|
|
356
|
+
const withoutTin = clients.filter(c => !c.tin);
|
|
357
|
+
|
|
358
|
+
// Сохранение в файл
|
|
359
|
+
import fs from 'fs';
|
|
360
|
+
fs.writeFileSync('clients.json', JSON.stringify(clients, null, 2));
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## 🏢 Получение профиля компании
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
const profile = await parser.getCompanyProfile();
|
|
367
|
+
console.log(profile);
|
|
368
|
+
// {
|
|
369
|
+
// name: "VEDA VECTOR",
|
|
370
|
+
// phone: "+998901234567",
|
|
371
|
+
// email: "info@vedavector.uz",
|
|
372
|
+
// address: ""
|
|
373
|
+
// }
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## 🔧 Продвинутые примеры
|
|
377
|
+
|
|
378
|
+
### Обработка ошибок
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
try {
|
|
382
|
+
await parser.ensureSession();
|
|
383
|
+
const invoices = await parser.getInvoices({
|
|
384
|
+
dateFrom: '2026-01-01',
|
|
385
|
+
dateTo: '2026-01-31'
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
console.log(`✅ Получено ${invoices.length} инвойсов`);
|
|
389
|
+
} catch (error) {
|
|
390
|
+
console.error('❌ Ошибка получения данных:', error.message);
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## 🔌 Интеграция с фреймворками
|
|
395
|
+
|
|
396
|
+
### NestJS
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
import { Injectable } from '@nestjs/common';
|
|
400
|
+
import { IikoParser } from 'vv-iiko-pp-parser';
|
|
401
|
+
|
|
402
|
+
@Injectable()
|
|
403
|
+
export class IikoService {
|
|
404
|
+
private parser: IikoParser;
|
|
405
|
+
|
|
406
|
+
constructor() {
|
|
407
|
+
this.parser = new IikoParser({
|
|
408
|
+
baseUrl: 'https://pp.iiko.uz',
|
|
409
|
+
language: 'en',
|
|
410
|
+
login: process.env.IIKO_PP_LOGIN!,
|
|
411
|
+
password: process.env.IIKO_PP_PASSWORD!
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
async getRecentInvoices() {
|
|
416
|
+
await this.parser.ensureSession();
|
|
417
|
+
return this.parser.getInvoices({
|
|
418
|
+
dateFrom: '2026-01-01',
|
|
419
|
+
dateTo: '2026-01-31'
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
## 🚨 Важные замечания
|
|
426
|
+
|
|
427
|
+
### Форматы tax_id
|
|
428
|
+
|
|
429
|
+
Используйте **точно такой же формат**, как отображается в системе:
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
// ✅ Правильно
|
|
433
|
+
searchValue: '305 845 090' // С пробелами
|
|
434
|
+
searchValue: '302 987 179' // С пробелами
|
|
435
|
+
|
|
436
|
+
// ❌ Неправильно
|
|
437
|
+
searchValue: '305845090' // Без пробелов
|
|
438
|
+
searchValue: '302987179' // Без пробелов
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Управление сессиями
|
|
442
|
+
|
|
443
|
+
Пакет автоматически:
|
|
444
|
+
- 🍪 Сохраняет cookies в файл
|
|
445
|
+
- 🔄 Восстанавливает сессию при перезапуске
|
|
446
|
+
- ✅ Проверяет валидность сессии
|
|
447
|
+
- 🔐 Переавторизуется при необходимости
|
|
448
|
+
|
|
449
|
+
## 📚 Примеры кода
|
|
450
|
+
|
|
451
|
+
Полные рабочие примеры доступны в папке [`examples/`](./examples/):
|
|
452
|
+
|
|
453
|
+
- [`basic.js`](./examples/basic.js) — Базовое использование
|
|
454
|
+
- [`filtering.js`](./examples/filtering.js) — Примеры фильтрации
|
|
455
|
+
- [`nestjs-service.ts`](./examples/nestjs-service.ts) — Интеграция с NestJS
|
|
456
|
+
|
|
457
|
+
## 🛡️ TypeScript
|
|
458
|
+
|
|
459
|
+
Пакет полностью типизирован и экспортирует все необходимые типы:
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
import {
|
|
463
|
+
IikoParser,
|
|
464
|
+
IikoParserOptions,
|
|
465
|
+
InvoicesFilter,
|
|
466
|
+
InvoiceData,
|
|
467
|
+
CompanyProfile
|
|
468
|
+
} from 'vv-iiko-pp-parser';
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
## 🐛 Устранение неполадок
|
|
472
|
+
|
|
473
|
+
### Ошибки авторизации
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
❌ Ошибка: Invalid credentials
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
**Решение**: Проверьте правильность логина и пароля в `.env` файле.
|
|
480
|
+
|
|
481
|
+
### Пустые результаты поиска
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
✅ Найдено 0 инвойсов
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
**Возможные причины**:
|
|
488
|
+
- Неправильный формат `tax_id` (должен быть с пробелами)
|
|
489
|
+
- Неправильный диапазон дат
|
|
490
|
+
- Инвойсы отсутствуют за указанный период
|
|
491
|
+
|
|
492
|
+
### Проблемы с сессиями
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
❌ Ошибка: Session expired
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
**Решение**: Пакет автоматически переавторизуется. Если проблема повторяется, очистите файл cookies:
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
rm -f .cookies.json
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
## � Progress Tracking
|
|
505
|
+
|
|
506
|
+
Вы можете подписаться на события прогресса выполнения для отслеживания состояния парсера:
|
|
507
|
+
|
|
508
|
+
```typescript
|
|
509
|
+
const parser = new IikoParser({
|
|
510
|
+
baseUrl: 'https://pp.iiko.uz',
|
|
511
|
+
login: process.env.IIKO_PP_LOGIN,
|
|
512
|
+
password: process.env.IIKO_PP_PASSWORD,
|
|
513
|
+
onProgress: (event) => {
|
|
514
|
+
console.log(`[${event.stage}] ${event.message}`);
|
|
515
|
+
|
|
516
|
+
if (event.current && event.total) {
|
|
517
|
+
const progress = Math.round((event.current / event.total) * 100);
|
|
518
|
+
console.log(`Progress: ${progress}% (${event.current}/${event.total})`);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (event.invoiceNumber) {
|
|
522
|
+
console.log(`Processing invoice: ${event.invoiceNumber}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### События прогресса
|
|
529
|
+
|
|
530
|
+
| Stage | Описание | Поля |
|
|
531
|
+
|-------|----------|------|
|
|
532
|
+
| `session` | Инициализация сессии | `message` |
|
|
533
|
+
| `auth` | Процесс авторизации | `message` |
|
|
534
|
+
| `fetch_invoices` | Загрузка страниц инвойсов | `message`, `current`, `total` |
|
|
535
|
+
| `parse_invoices` | Парсинг HTML страниц | `message` |
|
|
536
|
+
| `fetch_invoice_details` | Загрузка деталей инвойсов | `message`, `current`, `total`, `invoiceNumber` |
|
|
537
|
+
| `fetch_clients` | Загрузка страниц со списком клиентов | `message`, `current`, `total` |
|
|
538
|
+
| `parse_clients` | Парсинг списка клиентов | `message`, `current`, `total` |
|
|
539
|
+
| `fetch_client_details` | Загрузка профилей клиентов | `message`, `current`, `total` |
|
|
540
|
+
| `done` | Завершение работы | `message` |
|
|
541
|
+
|
|
542
|
+
### Интеграция с WebSocket/SSE
|
|
543
|
+
|
|
544
|
+
```typescript
|
|
545
|
+
// В NestJS с WebSocket
|
|
546
|
+
@WebSocketGateway()
|
|
547
|
+
export class ProgressGateway {
|
|
548
|
+
constructor(private parser: IikoParser) {
|
|
549
|
+
this.parser = new IikoParser({
|
|
550
|
+
// ... config
|
|
551
|
+
onProgress: (event) => {
|
|
552
|
+
this.server.emit('parser-progress', event);
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// В Express с SSE
|
|
559
|
+
app.get('/parse-progress', (req, res) => {
|
|
560
|
+
res.writeHead(200, {
|
|
561
|
+
'Content-Type': 'text/event-stream',
|
|
562
|
+
'Cache-Control': 'no-cache',
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
const parser = new IikoParser({
|
|
566
|
+
// ... config
|
|
567
|
+
onProgress: (event) => {
|
|
568
|
+
res.write(`data: ${JSON.stringify(event)}\n\n`);
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
// Start parsing...
|
|
573
|
+
});
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
## 📝 Лицензия
|
|
577
|
+
|
|
578
|
+
UNLICENSED
|
|
579
|
+
|
|
580
|
+
## ⚠️ Disclaimer
|
|
581
|
+
|
|
582
|
+
Это неофициальный пакет. Используйте в соответствии с условиями использования iiko Partner Portal.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { IikoSessionService } from '../core/session/iiko-session.service';
|
|
2
|
+
import { ClientsFetchParams } from './clients.types';
|
|
3
|
+
/**
|
|
4
|
+
* Сервис для загрузки HTML страниц клиентов из iiko Partner Portal.
|
|
5
|
+
*
|
|
6
|
+
* Выполняет HTTP GET запросы к endpoints:
|
|
7
|
+
* - AJAX endpoint для получения списка клиентов
|
|
8
|
+
* - Страница профиля клиента для получения деталей
|
|
9
|
+
*
|
|
10
|
+
* Использует авторизованный HTTP клиент с cookies из IikoSessionService.
|
|
11
|
+
*/
|
|
12
|
+
export declare class ClientsFetcher {
|
|
13
|
+
private readonly sessionService;
|
|
14
|
+
private readonly clientsListEndpoint;
|
|
15
|
+
private readonly clientAreaEndpoint;
|
|
16
|
+
private readonly cloudAllocationEndpoint;
|
|
17
|
+
private readonly saasAllocationEndpoint;
|
|
18
|
+
constructor(sessionService: IikoSessionService);
|
|
19
|
+
/**
|
|
20
|
+
* Выполняет HTTP GET запрос к AJAX endpoint для получения списка клиентов.
|
|
21
|
+
*
|
|
22
|
+
* Endpoint: GET /en/cabinet/ajax/clients-list.html
|
|
23
|
+
*
|
|
24
|
+
* Параметры запроса:
|
|
25
|
+
* - query: поисковая строка (фильтрует клиентов по имени или UID на сервере)
|
|
26
|
+
* - perPage: количество клиентов на странице (по умолчанию: 10)
|
|
27
|
+
* - page: номер страницы (по умолчанию: 1)
|
|
28
|
+
*
|
|
29
|
+
* Возвращаемый HTML содержит:
|
|
30
|
+
* - Полную HTML страницу с <div id="clientsTable_ajax"> (первый запрос)
|
|
31
|
+
* - ИЛИ только <tbody class="ajax"> фрагмент (последующие AJAX запросы)
|
|
32
|
+
*
|
|
33
|
+
* Предусловия:
|
|
34
|
+
* - Сессия должна быть инициализирована через sessionService.ensureSession()
|
|
35
|
+
* - HTTP клиент уже содержит валидные cookies
|
|
36
|
+
*
|
|
37
|
+
* @param params Опциональные параметры запроса (query, perPage, page)
|
|
38
|
+
* @returns Promise с HTML строкой со списком клиентов
|
|
39
|
+
* @throws Error если запрос вернул ошибку или невалидный ответ
|
|
40
|
+
*/
|
|
41
|
+
fetchClientsHtml(params?: ClientsFetchParams): Promise<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Загружает HTML страницу профиля конкретного клиента.
|
|
44
|
+
*
|
|
45
|
+
* Endpoint: GET /en/cabinet/client-area/index.html?clientId=XXX
|
|
46
|
+
*
|
|
47
|
+
* Возвращаемый HTML содержит:
|
|
48
|
+
* - UUID клиента (в кнопке "UID: XXX-XXX-XXX")
|
|
49
|
+
* - Версию iiko (в кнопке "Version iiko: X.X.XXXX")
|
|
50
|
+
* - Контактную информацию (email, phone в таблице)
|
|
51
|
+
* - Юридические данные (Legal entity и Company tax id в таблице)
|
|
52
|
+
* - Информацию о лицензиях и хостинге
|
|
53
|
+
*
|
|
54
|
+
* Предусловия:
|
|
55
|
+
* - Сессия должна быть инициализирована
|
|
56
|
+
* - Пользователь должен иметь доступ к данному clientId
|
|
57
|
+
*
|
|
58
|
+
* @param clientId ID клиента (целочисленный идентификатор)
|
|
59
|
+
* @returns Promise с HTML строкой страницы профиля клиента
|
|
60
|
+
* @throws Error если запрос вернул ошибку или клиент не найден
|
|
61
|
+
*/
|
|
62
|
+
fetchClientProfile(clientId: string): Promise<string>;
|
|
63
|
+
/**
|
|
64
|
+
* Загружает HTML страницу Cloud license allocation для chain.
|
|
65
|
+
*
|
|
66
|
+
* Endpoint: GET /en/cabinet/client-area/licenses/cloud-mapping.html?clientId=XXX
|
|
67
|
+
*
|
|
68
|
+
* Эта страница содержит таблицу "Store of the chain" с членами chain и их Cloud лицензиями.
|
|
69
|
+
* Каждая строка таблицы содержит:
|
|
70
|
+
* - Имя клиента (ссылка на client-area)
|
|
71
|
+
* - Input поле с количеством выделенных Cloud лицензий
|
|
72
|
+
*
|
|
73
|
+
* Предусловия:
|
|
74
|
+
* - Сессия должна быть инициализирована
|
|
75
|
+
* - clientId должен быть Chain (иметь Cloud license allocation)
|
|
76
|
+
*
|
|
77
|
+
* @param clientId ID chain для загрузки allocation
|
|
78
|
+
* @returns Promise с HTML строкой страницы cloud allocation
|
|
79
|
+
* @throws Error если запрос вернул ошибку или клиент не chain
|
|
80
|
+
*/
|
|
81
|
+
fetchCloudAllocationHtml(clientId: string): Promise<string>;
|
|
82
|
+
/**
|
|
83
|
+
* Загружает HTML страницу SaaS license allocation для chain.
|
|
84
|
+
*
|
|
85
|
+
* Endpoint: GET /en/cabinet/client-area/licenses/saas-mapping.html?clientId=XXX
|
|
86
|
+
*
|
|
87
|
+
* Эта страница содержит таблицу "Store of the chain" с членами chain и их SaaS лицензиями.
|
|
88
|
+
* Каждая строка таблицы содержит:
|
|
89
|
+
* - Имя клиента (ссылка на client-area)
|
|
90
|
+
* - Input поле с количеством выделенных SaaS лицензий
|
|
91
|
+
*
|
|
92
|
+
* Предусловия:
|
|
93
|
+
* - Сессия должна быть инициализирована
|
|
94
|
+
* - clientId должен быть Chain (иметь SaaS license allocation)
|
|
95
|
+
*
|
|
96
|
+
* @param clientId ID chain для загрузки allocation
|
|
97
|
+
* @returns Promise с HTML строкой страницы saas allocation
|
|
98
|
+
* @throws Error если запрос вернул ошибку или клиент не chain
|
|
99
|
+
*/
|
|
100
|
+
fetchSaasAllocationHtml(clientId: string): Promise<string>;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=clients.fetcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clients.fetcher.d.ts","sourceRoot":"","sources":["../../src/clients/clients.fetcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;GAQG;AACH,qBAAa,cAAc;IAMb,OAAO,CAAC,QAAQ,CAAC,cAAc;IAL3C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAwC;IAC5E,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAwC;IAC3E,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAyD;IACjG,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAwD;gBAElE,cAAc,EAAE,kBAAkB;IAE/D;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,gBAAgB,CAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IA2CpE;;;;;;;;;;;;;;;;;;;OAmBG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB3D;;;;;;;;;;;;;;;;;OAiBG;IACG,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAyBjE;;;;;;;;;;;;;;;;;OAiBG;IACG,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAwBjE"}
|