@pelygo/janus 0.1.2 → 0.3.0

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.
Files changed (5) hide show
  1. package/README.md +597 -170
  2. package/USAGE.md +376 -0
  3. package/dist/index.d.ts +1898 -11
  4. package/dist/index.js +593 -253
  5. package/package.json +3 -2
package/USAGE.md ADDED
@@ -0,0 +1,376 @@
1
+ # @pelygo/janus — Quick Usage Reference
2
+
3
+ This file ships inside the npm package for AI tools to reference.
4
+
5
+ ## Setup
6
+
7
+ ```js
8
+ import { createJanusApi } from '@pelygo/janus';
9
+ import { configure } from '@pelygo/auth/core';
10
+
11
+ // Auth and API are separate servers — both URLs required
12
+ configure({
13
+ apiBaseUrl: 'https://api.janus.dev.pelygo.com',
14
+ authBaseUrl: 'https://api.auth.dev.pelygo.com',
15
+ });
16
+
17
+ export const janus = createJanusApi({
18
+ baseUrl: 'https://api.janus.dev.pelygo.com',
19
+ onUnauthorized: () => {
20
+ setTimeout(() => { window.location.href = '/SignIn'; }, 100);
21
+ },
22
+ });
23
+ ```
24
+
25
+ ## Rules
26
+
27
+ 1. **Always pass `clientId`** to every query. Get it from `useClient()`:
28
+ ```js
29
+ const { clientId } = useClient();
30
+ ```
31
+ New endpoints reject without it (400). Older endpoints return ALL clients' data without it.
32
+
33
+ 2. **Use exact field names** from the tables below. Do not guess field names.
34
+
35
+ 3. **Navigation in callbacks** (onSuccess, onSelect, logout) must use:
36
+ ```js
37
+ setTimeout(() => { window.location.href = '/path'; }, 100);
38
+ ```
39
+ This is required for Base44 and other iframe-based environments.
40
+
41
+ 4. **Use `Object.entries(data)`** for dynamic response shapes (like `getStats`).
42
+
43
+ ## Query Filter Reference
44
+
45
+ ### PaginatedQueryFilters (v2 endpoints: products, stocks, locations, etc.)
46
+
47
+ | Param | Type | Description |
48
+ |-------|------|-------------|
49
+ | `clientId` | `number` | **Required.** Client ID from `useClient()` |
50
+ | `pageSize` | `number` | Results per page (default: 25) |
51
+ | `pageNumber` | `number` | Page number, 1-based (default: 1) |
52
+ | `orderColumn` | `string` | Column to sort by (e.g. `'id'`, `'created'`) |
53
+ | `orderDirection` | `'ASC' \| 'DESC'` | Sort direction (default: DESC) |
54
+ | `query` | `string` | Free-text search across key fields |
55
+
56
+ ```js
57
+ const { data, meta } = await janus.products.getAll({
58
+ clientId, pageSize: 25, pageNumber: 1, orderDirection: 'DESC', query: 'widget',
59
+ });
60
+ ```
61
+
62
+ ### ReturnsQueryFilters (janus.returns.query)
63
+
64
+ | Param | Type | Description |
65
+ |-------|------|-------------|
66
+ | `clientId` | `number` | Client ID |
67
+ | `page` | `number` | Page number |
68
+ | `pageSize` | `number` | Results per page |
69
+ | `created_at` | `string` | Start date (ISO, e.g. `'2025-01-01'`) |
70
+ | `created_to` | `string` | End date (ISO) |
71
+ | `last_status_ids` | `string` | Comma-separated status IDs to match current status |
72
+ | `include_status_ids` | `string` | Include returns with any of these status IDs |
73
+ | `exclude_status_ids` | `string` | Exclude returns with these status IDs |
74
+ | `include_associations` | `string` | Include nested data: `'return_items'`, `'return_comments'`, or both comma-separated |
75
+ | `csv` | `boolean` | Export as CSV instead of JSON |
76
+ | `group_by` | `string` | Group results by field |
77
+
78
+ ```js
79
+ const returns = await janus.returns.query({
80
+ clientId, page: 1, pageSize: 25,
81
+ created_at: '2025-01-01', created_to: '2025-12-31',
82
+ last_status_ids: '1,2', include_associations: 'return_items',
83
+ });
84
+ ```
85
+
86
+ ### OrdersQueryFilters (janus.orders.getAll)
87
+
88
+ | Param | Type | Description |
89
+ |-------|------|-------------|
90
+ | `clientId` | `number` | Client ID |
91
+ | `page` | `number` | Page number |
92
+ | `pageSize` | `number` | Results per page |
93
+ | `order_column` | `string` | Sort column |
94
+ | `order_direction` | `'ASC' \| 'DESC'` | Sort direction |
95
+ | `created_at` | `string` | Start date (ISO) |
96
+ | `created_to` | `string` | End date (ISO) |
97
+ | `channel` | `string` | Filter by sales channel |
98
+ | `courier` | `string` | Filter by courier name |
99
+ | `status` | `string` | Filter by order status |
100
+ | `query` | `string` | Free-text search |
101
+
102
+ ```js
103
+ const orders = await janus.orders.getAll({
104
+ clientId, page: 1, pageSize: 25, order_direction: 'DESC',
105
+ created_at: '2025-01-01', created_to: '2025-12-31', query: 'ORD-123',
106
+ });
107
+ ```
108
+
109
+ ### ReturnsSummaryFilters (janus.reports.returnsSummary)
110
+
111
+ | Param | Type | Description |
112
+ |-------|------|-------------|
113
+ | `clientId` | `number` | Client ID |
114
+ | `createdFrom` | `string` | Start date (ISO) |
115
+ | `createdTo` | `string` | End date (ISO) |
116
+ | `approvedFrom` | `string` | Approval start date |
117
+ | `approvedTo` | `string` | Approval end date |
118
+ | `courierServiceId` | `number` | Filter by courier service |
119
+ | `approved` | `boolean` | Only approved returns |
120
+ | `page` | `number` | Page number |
121
+ | `pageSize` | `number` | Results per page |
122
+ | `csv` | `boolean` | Set true for CSV export (use `returnsSummaryCsv` instead) |
123
+
124
+ ```js
125
+ const summary = await janus.reports.returnsSummary({
126
+ clientId, createdFrom: '2025-01-01', createdTo: '2025-12-31',
127
+ });
128
+ ```
129
+
130
+ ### Resource-specific extra filters
131
+
132
+ | Resource | Extra param | Type | Description |
133
+ |----------|-----------|------|-------------|
134
+ | `janus.stockTransactions.getAll` | `stockId` | `number` | Filter by stock record |
135
+ | `janus.stockAllocations.getAll` | `orderId` | `number` | Filter by order |
136
+ | `janus.dispatches.getAll` | `orderId` | `number` | Filter by order |
137
+ | `janus.audits.getAll` | `filter` | `string` | Additional filter |
138
+ | `janus.users.getAll` | `filterRole` | `string` | Filter by role |
139
+ | `janus.users.getAll` | `filterType` | `string` | Filter by user type |
140
+ | `janus.users.getAll` | `filterClientId` | `number` | Filter by assigned client |
141
+
142
+ ## All Resources
143
+
144
+ | Resource | Access | Description |
145
+ |----------|--------|-------------|
146
+ | `janus.clients` | Auth | Client CRUD, courier services, return reasons, integrations, files |
147
+ | `janus.returns` | Auth | Returns CRUD, items, comments, statuses, reasons, categories, sources |
148
+ | `janus.orders` | Auth | Order queries, stats, returns, filter options, CRUD |
149
+ | `janus.reports` | Auth | Returns summary/reasons/overview/stats + CSV exports |
150
+ | `janus.products` | Auth | Product CRUD (preferred over legacy.queryProducts) |
151
+ | `janus.productCategories` | Auth | Product category CRUD |
152
+ | `janus.stocks` | Auth | Stock record CRUD |
153
+ | `janus.stockTransactions` | Auth | Stock movement CRUD |
154
+ | `janus.stockAllocations` | Auth | Stock allocation CRUD (no delete) |
155
+ | `janus.locations` | Auth | Warehouse location CRUD |
156
+ | `janus.audits` | Auth | Audit trail (read-only) |
157
+ | `janus.asns` | Auth | ASNs with nested lines and receipts |
158
+ | `janus.dispatches` | Auth | Dispatch CRUD |
159
+ | `janus.consignments` | Auth | Consignment tracking |
160
+ | `janus.invoices` | Auth | Invoices with nested line items |
161
+ | `janus.users` | Auth | User CRUD, password management |
162
+ | `janus.couriers` | Auth | Courier and service management |
163
+ | `janus.integrations` | Auth | Integration management |
164
+ | `janus.logs` | Auth | Activity and issue logging |
165
+ | `janus.tasks` | Auth | Task history |
166
+ | `janus.legacy` | Auth | Legacy couriers, post services, products (deprecated) |
167
+ | `janus.helpers` | Public | Client settings, notifications |
168
+ | `janus.customer` | Public | Customer tracking and login |
169
+
170
+ ## Return Entity Fields
171
+
172
+ | Field | Type | Description |
173
+ |-------|------|-------------|
174
+ | `id` | `number` | Unique ID |
175
+ | `return_reference` | `string` | Return reference number |
176
+ | `wms_order_ref` | `string` | Original order reference |
177
+ | `customername` | `string` | Full customer name |
178
+ | `forename` | `string` | First name |
179
+ | `surname` | `string` | Last name |
180
+ | `email` | `string` | Customer email |
181
+ | `approval_status` | `string` | "pending", "approved", or "rejected" |
182
+ | `tracking_number` | `string` | Courier tracking number |
183
+ | `latestStatus` | `object` | `{ name: string }` — current status |
184
+ | `return_items` | `array` | Line items (when include_associations set) |
185
+ | `created_ts` | `string` | ISO timestamp |
186
+ | `updated_ts` | `string` | ISO timestamp |
187
+
188
+ ## Order Entity Fields
189
+
190
+ | Field | Type | Description |
191
+ |-------|------|-------------|
192
+ | `id` | `number` | Order ID |
193
+ | `reference` | `string` | Order reference number |
194
+ | `channel` | `string` | Sales channel ("shopify", "amazon", etc.) |
195
+ | `transaction_type` | `string` | "b2c", "b2b", "internal_transfer", "damage", "expiry" |
196
+ | `orderDate` | `string` | ISO date when order was placed |
197
+ | `orderStatus` | `number` | Numeric status code |
198
+ | `notes` | `string` | Order notes |
199
+ | `hold` | `number` | 0 = not on hold, 1 = on hold |
200
+ | `draft` | `number` | 0 = confirmed, 1 = draft |
201
+ | `created` | `string` | ISO date when created |
202
+ | `modified` | `string` | ISO date when last modified |
203
+ | `orderItems` | `array` | Order line items |
204
+ | `dispatches` | `array` | Dispatch records |
205
+
206
+ ## Product Entity Fields (from /products endpoint)
207
+
208
+ | Field | Type | Description |
209
+ |-------|------|-------------|
210
+ | `product_id` | `number` | Product ID |
211
+ | `client_id` | `number` | Client ID |
212
+ | `sku_code` | `string` | Product SKU |
213
+ | `product_name` | `string` | Product name |
214
+ | `description` | `string` | Product description |
215
+ | `barcode` | `string` | Barcode (EAN/UPC) |
216
+ | `price` | `number` | Unit price |
217
+ | `currency` | `string` | Currency code ("GBP", "USD") |
218
+ | `weight_grams` | `number` | Weight in grams |
219
+ | `product_status` | `string` | "active", "discontinued", "inactive", "archived" |
220
+ | `product_type` | `string` | "sellable_unit", "packaging", "component", "consumables" |
221
+ | `stock` | `number` | Current stock level |
222
+ | `image_url` | `string` | Product image URL |
223
+ | `low_stock_threshold` | `number` | Low stock alert threshold |
224
+ | `created_date` | `string` | ISO date |
225
+ | `updated_date` | `string` | ISO date |
226
+
227
+ ## Stock Entity Fields
228
+
229
+ | Field | Type | Description |
230
+ |-------|------|-------------|
231
+ | `id` | `number` | Stock record ID |
232
+ | `clientId` | `number` | Client ID |
233
+ | `sku_code` | `string` | Product SKU |
234
+ | `location` | `string` | Storage location |
235
+ | `quantity` | `number` | Current quantity |
236
+ | `batch_number` | `string` | Batch/lot number |
237
+ | `serial_number` | `string` | Serial number |
238
+ | `best_before_date` | `string` | ISO date |
239
+ | `stock_status` | `string` | "available", "quarantined", "expired", "damaged", "reserved" |
240
+ | `fulfilment_location_name` | `string` | Warehouse name |
241
+ | `notes` | `string` | Notes |
242
+
243
+ ## Invoice Entity Fields
244
+
245
+ | Field | Type | Description |
246
+ |-------|------|-------------|
247
+ | `id` | `number` | Invoice ID |
248
+ | `clientId` | `number` | Client ID |
249
+ | `invoice_date` | `string` | ISO date |
250
+ | `xero_reference` | `string` | Xero accounting reference |
251
+ | `total` | `number` | Total amount |
252
+ | `emailed` | `number` | 0 = not emailed, 1 = emailed |
253
+ | `paid` | `number` | 0 = unpaid, 1 = paid |
254
+ | `invoiceLines` | `array` | Line items |
255
+
256
+ ## ReturnsStatsResponse Fields
257
+
258
+ ```js
259
+ const stats = await janus.reports.returnsStats(clientId);
260
+ // stats = {
261
+ // total: 150,
262
+ // awaiting_processing: 12,
263
+ // in_progress: 25,
264
+ // completed: 100,
265
+ // awaiting_approval: 5,
266
+ // approved: 90,
267
+ // rejected: 8,
268
+ // by_status: { "Processing": 25, "Complete": 100, ... },
269
+ // by_reason: { "Faulty": 30, "Wrong item": 20, ... }
270
+ // }
271
+ ```
272
+
273
+ ## OrdersStatsResponse Fields
274
+
275
+ ```js
276
+ const stats = await janus.orders.getStats({ clientId, dashboard: true });
277
+ // Returns a flat object with numeric counts — keys vary by data.
278
+ // Use Object.entries(stats) to iterate. Do NOT hardcode field names.
279
+ // Example: { total_orders: 150, dispatched: 120, processing: 15, ... }
280
+ ```
281
+
282
+ ## API Behaviour Notes
283
+
284
+ ### Error response format
285
+ All errors follow this shape:
286
+ ```json
287
+ { "statusCode": 400, "message": "Error description" }
288
+ ```
289
+ Common codes: 400 (bad request/validation), 401 (unauthorized), 404 (not found).
290
+
291
+ ### Date formats
292
+ - **Query params:** ISO 8601 (`'2025-01-01'` or `'2025-01-01 12:00:00'`)
293
+ - **Response fields:** ISO 8601 timestamps (e.g. `created_ts`, `orderDate`, `created`)
294
+ - **CSV exports:** formatted as `DD-MM-YYYY HH:mm`
295
+
296
+ ### Pagination defaults
297
+ - Default `pageSize`: 50 (v2 endpoints), varies for legacy
298
+ - Default `pageNumber`: 1 (1-based indexing)
299
+ - Default sort: DESC (newest first)
300
+
301
+ ### Search behaviour (`query` param)
302
+ Free-text search is case-insensitive LIKE matching across key text columns:
303
+ - Products: searches `sku`, `name`, `description`
304
+ - Returns: searches order references, tracking numbers
305
+ - Clients: searches client names
306
+
307
+ ### Returns default behaviour
308
+ - Archived returns (status 10) are **excluded by default** — pass `include_archived: true` to include them
309
+ - Returns with `return_type: 0` are regular returns, `return_type: 1` are exchanges
310
+ - `include_associations: 'return_items'` eagerly loads line items; `'return_items,return_comments'` loads both
311
+
312
+ ### Stats responses
313
+ `getStats` endpoints return flat objects with numeric values. The keys vary based on the client's data. **Always use `Object.entries(stats)` to iterate — never hardcode expected keys.**
314
+
315
+ ## Common Patterns
316
+
317
+ ### Paginated list query
318
+ ```js
319
+ const { data, meta } = await janus.products.getAll({
320
+ clientId,
321
+ pageSize: 25,
322
+ pageNumber: 1,
323
+ orderDirection: 'DESC',
324
+ query: searchText,
325
+ });
326
+ // meta = { total_items, total_pages, current_page, page_size }
327
+ ```
328
+
329
+ ### CSV export
330
+ ```js
331
+ const csv = await janus.reports.returnsSummaryCsv({ clientId, createdFrom, createdTo });
332
+ const blob = new Blob([csv], { type: 'text/csv' });
333
+ const url = URL.createObjectURL(blob);
334
+ const a = document.createElement('a');
335
+ a.href = url;
336
+ a.download = 'export.csv';
337
+ a.click();
338
+ URL.revokeObjectURL(url);
339
+ ```
340
+
341
+ ### Login page
342
+ ```jsx
343
+ import { LoginForm } from '@pelygo/auth/react';
344
+
345
+ <LoginForm
346
+ onSuccess={() => setTimeout(() => { window.location.href = '/clients'; }, 100)}
347
+ onError={(error) => console.log('Login error:', error)}
348
+ />
349
+ ```
350
+
351
+ ### Client selection
352
+ ```jsx
353
+ import { SelectClientForm } from '@pelygo/auth/react';
354
+
355
+ <SelectClientForm
356
+ onSelect={() => setTimeout(() => { window.location.href = '/dashboard'; }, 100)}
357
+ />
358
+ ```
359
+
360
+ ### Route guard (must check isLoading)
361
+ ```jsx
362
+ const { isAuthenticated, isLoading } = useAuth();
363
+ const { requiresClientSelection, hasSelectedClient } = useClient();
364
+
365
+ if (isLoading) return <LoadingSpinner />;
366
+ if (!isAuthenticated) return <Navigate to="/SignIn" replace />;
367
+ if (requiresClientSelection && !hasSelectedClient) return <Navigate to="/clients" replace />;
368
+ ```
369
+
370
+ ### Logout
371
+ ```jsx
372
+ onClick={() => {
373
+ logout();
374
+ setTimeout(() => { window.location.href = '/SignIn'; }, 100);
375
+ }}
376
+ ```