@pelygo/janus 0.2.0 → 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.
- package/README.md +597 -170
- package/USAGE.md +376 -0
- package/dist/index.d.ts +54 -6
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,263 +1,690 @@
|
|
|
1
1
|
# @pelygo/janus
|
|
2
2
|
|
|
3
|
-
TypeScript API client for JANUS (VCOMSUITE backend)
|
|
3
|
+
TypeScript API client for JANUS (VCOMSUITE warehouse management backend). Provides typed access to orders, returns, products, stock, invoices, ASNs, dispatches, and more.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
### Install
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
10
|
npm install @pelygo/janus @pelygo/auth
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
`@pelygo/auth` is a required peer dependency. It handles token storage and refresh automatically.
|
|
14
|
+
|
|
15
|
+
### Configure
|
|
16
|
+
|
|
17
|
+
The JANUS API server and the auth server are **different hosts**. You must provide both URLs.
|
|
12
18
|
|
|
13
19
|
```typescript
|
|
14
20
|
import { createJanusApi } from '@pelygo/janus';
|
|
15
21
|
|
|
16
|
-
// Create API instance
|
|
17
22
|
const janus = createJanusApi({
|
|
18
|
-
baseUrl: 'https://api.janus.pelygo.com',
|
|
23
|
+
baseUrl: 'https://api.janus.pelygo.com', // JANUS API server
|
|
24
|
+
authUrl: 'https://auth.pelygo.com', // Auth server (different host)
|
|
19
25
|
onUnauthorized: () => {
|
|
20
|
-
//
|
|
26
|
+
// IMPORTANT: use setTimeout in Base44/iframe environments
|
|
27
|
+
setTimeout(() => window.location.href = '/login', 0);
|
|
21
28
|
},
|
|
22
29
|
});
|
|
23
|
-
|
|
24
|
-
// Authenticate
|
|
25
|
-
await janus.auth.login('username', 'password');
|
|
26
|
-
|
|
27
|
-
// Use typed resources
|
|
28
|
-
const clients = await janus.clients.getAll();
|
|
29
|
-
const returns = await janus.returns.query({ clientId: 5, pageSize: 50 });
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
### Creating the Client
|
|
32
|
+
**Dev environment:**
|
|
35
33
|
|
|
36
34
|
```typescript
|
|
37
35
|
const janus = createJanusApi({
|
|
38
|
-
baseUrl:
|
|
39
|
-
|
|
36
|
+
baseUrl: 'https://api.janus.dev.pelygo.com',
|
|
37
|
+
authUrl: 'https://auth.dev.pelygo.com',
|
|
40
38
|
});
|
|
41
39
|
```
|
|
42
40
|
|
|
43
|
-
###
|
|
44
|
-
|
|
45
|
-
The client wraps `@pelygo/auth` for authentication:
|
|
41
|
+
### Authenticate
|
|
46
42
|
|
|
47
43
|
```typescript
|
|
48
|
-
|
|
49
|
-
await janus.auth.login(username, password);
|
|
50
|
-
|
|
51
|
-
// Get current user
|
|
44
|
+
await janus.auth.login('username', 'password');
|
|
52
45
|
const user = await janus.auth.getUser();
|
|
53
|
-
|
|
54
|
-
// Logout
|
|
55
|
-
await janus.auth.logout();
|
|
56
|
-
|
|
57
|
-
// Check if authenticated
|
|
58
46
|
const isLoggedIn = janus.auth.isAuthenticated();
|
|
47
|
+
await janus.auth.logout();
|
|
59
48
|
```
|
|
60
49
|
|
|
61
|
-
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## All Available Resources
|
|
53
|
+
|
|
54
|
+
| Resource | Accessor | Auth | Description |
|
|
55
|
+
|----------|----------|------|-------------|
|
|
56
|
+
| Clients | `janus.clients` | Yes | Client account CRUD, courier services per client |
|
|
57
|
+
| Returns | `janus.returns` | Yes | Full returns management: CRUD, items, comments, statuses, reasons, categories, sources |
|
|
58
|
+
| Orders | `janus.orders` | Yes | Query orders, stats, filter options, create/update |
|
|
59
|
+
| Products | `janus.products` | Yes | Product CRUD (preferred over `legacy.queryProducts`) |
|
|
60
|
+
| Product Categories | `janus.productCategories` | Yes | Product category CRUD |
|
|
61
|
+
| Stocks | `janus.stocks` | Yes | Stock record CRUD |
|
|
62
|
+
| Stock Transactions | `janus.stockTransactions` | Yes | Stock transaction history |
|
|
63
|
+
| Stock Allocations | `janus.stockAllocations` | Yes | Stock allocation records |
|
|
64
|
+
| Locations | `janus.locations` | Yes | Warehouse location CRUD |
|
|
65
|
+
| Dispatches | `janus.dispatches` | Yes | Dispatch CRUD |
|
|
66
|
+
| Consignments | `janus.consignments` | Yes | Consignment records |
|
|
67
|
+
| Invoices | `janus.invoices` | Yes | Invoice CRUD with line items |
|
|
68
|
+
| ASNs | `janus.asns` | Yes | Advance Shipping Notices with lines and receipts |
|
|
69
|
+
| Couriers | `janus.couriers` | Yes | Courier and service management |
|
|
70
|
+
| Reports | `janus.reports` | Yes | Returns summary, reasons, overview reports (JSON + CSV) |
|
|
71
|
+
| Integrations | `janus.integrations` | Yes | Integration management |
|
|
72
|
+
| Users | `janus.users` | Yes | User management |
|
|
73
|
+
| Logs | `janus.logs` | Yes | Activity and order issue logs |
|
|
74
|
+
| Tasks | `janus.tasks` | Yes | Task history |
|
|
75
|
+
| Audits | `janus.audits` | Yes | Audit trail (read-only) |
|
|
76
|
+
| Legacy | `janus.legacy` | Yes | Legacy couriers, post services, products |
|
|
77
|
+
| Helpers | `janus.helpers` | No | Public endpoints: return portal form submission, notification settings |
|
|
78
|
+
| Customer | `janus.customer` | No | Public customer tracking (order lookup) |
|
|
79
|
+
| Auth | `janus.auth` | -- | Underlying AuthApi instance for raw requests |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Entity Field Reference
|
|
84
|
+
|
|
85
|
+
### Return
|
|
86
|
+
|
|
87
|
+
| Field | Type | Description |
|
|
88
|
+
|-------|------|-------------|
|
|
89
|
+
| `id` | `number` | Unique ID |
|
|
90
|
+
| `return_reference` | `string?` | Human-readable return reference |
|
|
91
|
+
| `wms_order_ref` | `string?` | Original order reference |
|
|
92
|
+
| `client_id` | `number?` | Client ID |
|
|
93
|
+
| `status_id` | `number?` | Current status ID |
|
|
94
|
+
| `reason_id` | `number?` | Return reason ID |
|
|
95
|
+
| `customername` | `string?` | Full customer name |
|
|
96
|
+
| `forename` | `string?` | First name |
|
|
97
|
+
| `surname` | `string?` | Last name |
|
|
98
|
+
| `email` | `string?` | Customer email |
|
|
99
|
+
| `tracking_number` | `string?` | Courier tracking number |
|
|
100
|
+
| `tracking_url` | `string?` | Tracking page URL |
|
|
101
|
+
| `approval_status` | `'pending' \| 'approved' \| 'rejected'?` | Approval state |
|
|
102
|
+
| `approved` | `boolean?` | Whether approved |
|
|
103
|
+
| `approved_ts` | `string?` | Approval timestamp |
|
|
104
|
+
| `line_1` | `string?` | Address line 1 |
|
|
105
|
+
| `line_2` | `string?` | Address line 2 |
|
|
106
|
+
| `line_3` | `string?` | Address line 3 |
|
|
107
|
+
| `city` | `string?` | City |
|
|
108
|
+
| `county` | `string?` | County/state |
|
|
109
|
+
| `country` | `string?` | Country name |
|
|
110
|
+
| `country_code` | `string?` | ISO country code (e.g. `"GB"`) |
|
|
111
|
+
| `postcode` | `string?` | Postal code |
|
|
112
|
+
| `company` | `string?` | Company name |
|
|
113
|
+
| `wms_service_cost` | `number?` | WMS service cost |
|
|
114
|
+
| `courier_service_cost` | `number?` | Courier service cost |
|
|
115
|
+
| `courier_service_id` | `number?` | Assigned courier service ID |
|
|
116
|
+
| `items` | `ReturnItem[]?` | Line items (when included) |
|
|
117
|
+
| `statuses` | `ReturnStatusHistory[]?` | Status history (when included) |
|
|
118
|
+
| `comments` | `ReturnComment[]?` | Comments (when included) |
|
|
119
|
+
| `latestStatus` | `ReturnStatusHistory?` | Most recent status |
|
|
120
|
+
| `created_ts` | `string?` | ISO timestamp |
|
|
121
|
+
| `updated_ts` | `string?` | ISO timestamp |
|
|
122
|
+
|
|
123
|
+
### LegacyOrder
|
|
124
|
+
|
|
125
|
+
| Field | Type | Description |
|
|
126
|
+
|-------|------|-------------|
|
|
127
|
+
| `id` | `number` | Primary key |
|
|
128
|
+
| `customerId` | `number?` | FK to customer |
|
|
129
|
+
| `reference` | `string?` | Order reference string |
|
|
130
|
+
| `source` | `number?` | Source ID |
|
|
131
|
+
| `orderDate` | `string?` | ISO date the order was placed |
|
|
132
|
+
| `dispatchCompletedDate` | `string?` | ISO date all dispatches completed |
|
|
133
|
+
| `orderStatus` | `number?` | Numeric status code |
|
|
134
|
+
| `postServiceId` | `number?` | FK to shipping service |
|
|
135
|
+
| `courierId` | `number?` | FK to courier |
|
|
136
|
+
| `actualWeight` | `number?` | Measured weight |
|
|
137
|
+
| `notes` | `string?` | Internal notes |
|
|
138
|
+
| `hold` | `unknown?` | Whether order is on hold |
|
|
139
|
+
| `releaseDate` | `string?` | ISO date when hold was released |
|
|
140
|
+
| `draft` | `unknown?` | Whether order is a draft |
|
|
141
|
+
| `giftMessage` | `string?` | Gift message text |
|
|
142
|
+
| `deliveryInstructions` | `string?` | Delivery instructions |
|
|
143
|
+
| `orderIssue` | `number?` | Issue flag |
|
|
144
|
+
| `deliveryTerms` | `string?` | Incoterms code (e.g. `"DAP"`) |
|
|
145
|
+
| `transaction_type` | `'b2c' \| 'b2b' \| 'internal_transfer' \| 'damage' \| 'expiry'` | **Required.** Transaction classification |
|
|
146
|
+
| `external_order_id` | `string?` | External system order ID |
|
|
147
|
+
| `channel_order_id` | `string?` | Sales channel order ID |
|
|
148
|
+
| `channel` | `string?` | Sales channel name |
|
|
149
|
+
| `created` | `string?` | ISO created timestamp |
|
|
150
|
+
| `modified` | `string?` | ISO modified timestamp |
|
|
151
|
+
| `status` | `number?` | Record status (0 = inactive, 1 = active) |
|
|
152
|
+
| `orderItems` | `LegacyOrderItem[]` | Line items |
|
|
153
|
+
| `orderMeta` | `LegacyOrderMeta[]` | Metadata key-value pairs |
|
|
154
|
+
| `shopperDeliveryAddress` | `LegacyShopperAddress` | Delivery address |
|
|
155
|
+
| `shopperBillingAddress` | `LegacyShopperAddress` | Billing address |
|
|
156
|
+
| `dispatches` | `LegacyDispatch[]` | All dispatches for this order |
|
|
157
|
+
| `dispatch` | `LegacyDispatch` | Primary dispatch |
|
|
158
|
+
| `orderSource` | `Source` | Source reference data |
|
|
159
|
+
|
|
160
|
+
### LegacyDispatch
|
|
161
|
+
|
|
162
|
+
| Field | Type | Description |
|
|
163
|
+
|-------|------|-------------|
|
|
164
|
+
| `id` | `number` | Primary key |
|
|
165
|
+
| `orderId` | `number?` | FK to parent order |
|
|
166
|
+
| `reference` | `string?` | Client-facing reference code |
|
|
167
|
+
| `dispatchDate` | `string?` | ISO date shipped |
|
|
168
|
+
| `dispatchStatus` | `number?` | 0 = pending, 1 = dispatched, 2 = cancelled |
|
|
169
|
+
| `trackingNumber` | `string?` | Carrier tracking number |
|
|
170
|
+
| `actualWeight` | `number?` | Measured weight |
|
|
171
|
+
| `courierId` | `number?` | FK to courier |
|
|
172
|
+
| `postServiceId` | `number?` | FK to shipping service |
|
|
173
|
+
| `notes` | `string?` | Internal notes |
|
|
174
|
+
| `hold` | `unknown?` | 0 = not held, 1 = on hold |
|
|
175
|
+
| `draft` | `unknown?` | 0 = finalised, 1 = draft |
|
|
176
|
+
| `deliveryInstructions` | `string?` | Special delivery instructions |
|
|
177
|
+
| `dispatchActionId` | `number?` | Current action (pick, pack, ship) |
|
|
178
|
+
| `dispatchActionStatus` | `number?` | 0 = not started, 1 = in progress, 2 = completed |
|
|
179
|
+
| `stockStatus` | `number?` | 0 = unallocated, 1 = partial, 2 = fully allocated |
|
|
180
|
+
| `dispatchIssue` | `number?` | 0 = no issue, 1 = issue flagged |
|
|
181
|
+
| `priority` | `number?` | Higher = higher priority |
|
|
182
|
+
| `complete` | `number?` | 0 = incomplete, 1 = complete |
|
|
183
|
+
| `complete_date` | `string?` | ISO date marked complete |
|
|
184
|
+
| `deliveryTerms` | `string?` | Incoterms code |
|
|
185
|
+
| `created` | `string?` | ISO created timestamp |
|
|
186
|
+
| `modified` | `string?` | ISO modified timestamp |
|
|
187
|
+
| `status` | `number?` | 0 = inactive/deleted, 1 = active |
|
|
188
|
+
| `dispatchItems` | `LegacyDispatchItem[]` | Line items in this dispatch |
|
|
189
|
+
| `shopperDeliveryAddress` | `LegacyShopperAddress` | Delivery address |
|
|
190
|
+
| `consignment` | `Consignment` | Consignment record |
|
|
191
|
+
| `postService` | `LegacyPostService` | Shipping service details |
|
|
192
|
+
|
|
193
|
+
### FormattedProduct
|
|
194
|
+
|
|
195
|
+
Returned by `janus.products.getAll()`. Field names are snake_case (different from the raw `LegacyProduct` entity).
|
|
196
|
+
|
|
197
|
+
| Field | Type | Description |
|
|
198
|
+
|-------|------|-------------|
|
|
199
|
+
| `product_id` | `number` | Primary key |
|
|
200
|
+
| `client_id` | `number` | FK to owning client |
|
|
201
|
+
| `sku_code` | `string?` | SKU -- unique product identifier within the client |
|
|
202
|
+
| `product_name` | `string?` | Human-readable name |
|
|
203
|
+
| `description` | `string?` | Extended description |
|
|
204
|
+
| `additional_skus` | `string?` | Comma-separated alternative SKUs |
|
|
205
|
+
| `asins` | `string?` | Amazon Standard Identification Numbers |
|
|
206
|
+
| `custom_fields` | `Record<string, unknown>?` | Client-defined key-value pairs |
|
|
207
|
+
| `hs_code` | `string?` | Harmonized System code for customs |
|
|
208
|
+
| `unit_of_measure` | `string?` | e.g. `"each"`, `"kg"`, `"litre"` |
|
|
209
|
+
| `eaches_per_pack` | `number?` | Units per case pack |
|
|
210
|
+
| `case_pack_sku_code` | `string?` | SKU of the case pack |
|
|
211
|
+
| `weight_grams` | `number?` | Unit weight in grams |
|
|
212
|
+
| `barcode` | `string?` | Primary EAN/UPC barcode |
|
|
213
|
+
| `case_pack_barcode` | `string?` | Case pack barcode |
|
|
214
|
+
| `product_category_id` | `number?` | FK to product category |
|
|
215
|
+
| `product_type` | `string?` | e.g. `"physical"`, `"digital"`, `"service"` |
|
|
216
|
+
| `sellable_format` | `string?` | e.g. `"single"`, `"pack"`, `"case"` |
|
|
217
|
+
| `commodity_description` | `string?` | Customs commodity description |
|
|
218
|
+
| `price` | `number?` | Unit sale price |
|
|
219
|
+
| `currency` | `string?` | ISO 4217 code (e.g. `"GBP"`) |
|
|
220
|
+
| `country_of_origin` | `string?` | ISO 3166-1 alpha-2 (e.g. `"CN"`) |
|
|
221
|
+
| `primary_material` | `string?` | Primary material |
|
|
222
|
+
| `secondary_material` | `string?` | Secondary material |
|
|
223
|
+
| `dangerous_goods` | `string?` | DG classification / UN number |
|
|
224
|
+
| `image_url` | `string?` | Product image URL |
|
|
225
|
+
| `low_stock_threshold` | `number?` | Low-stock alert threshold |
|
|
226
|
+
| `requires_batch_tracking` | `number?` | 0 = no, 1 = yes |
|
|
227
|
+
| `requires_serial_tracking` | `number?` | 0 = no, 1 = yes |
|
|
228
|
+
| `requires_bbe_tracking` | `number?` | 0 = no, 1 = yes (best-before/expiry) |
|
|
229
|
+
| `is_bundle` | `number?` | 0 = standalone, 1 = bundle |
|
|
230
|
+
| `bundle_components` | `string?` | Component SKUs and quantities |
|
|
231
|
+
| `default_stock_status` | `string?` | Status assigned on receipt |
|
|
232
|
+
| `product_status` | `string?` | e.g. `"active"`, `"discontinued"` |
|
|
233
|
+
| `status` | `number?` | 0 = inactive/deleted, 1 = active |
|
|
234
|
+
| `created_date` | `string?` | ISO created timestamp |
|
|
235
|
+
| `updated_date` | `string?` | ISO updated timestamp |
|
|
236
|
+
|
|
237
|
+
### Stock
|
|
238
|
+
|
|
239
|
+
Extends `BaseEntity` (adds `id`, `created_by`, `updated_by`, `created_ts`, `updated_ts`, `partition_id`).
|
|
240
|
+
|
|
241
|
+
| Field | Type | Description |
|
|
242
|
+
|-------|------|-------------|
|
|
243
|
+
| `id` | `number` | Primary key (from BaseEntity) |
|
|
244
|
+
| `clientId` | `number?` | FK to owning client |
|
|
245
|
+
| `sku_code` | `string?` | SKU identifying the product |
|
|
246
|
+
| `location` | `string?` | Location code (e.g. `"A-01-03-B"`) |
|
|
247
|
+
| `quantity` | `number?` | Units at this location |
|
|
248
|
+
| `batch_number` | `string?` | Batch/lot number |
|
|
249
|
+
| `serial_number` | `string?` | Serial number |
|
|
250
|
+
| `best_before_date` | `string?` | ISO expiry date (FEFO rotation) |
|
|
251
|
+
| `received_date` | `string?` | ISO date received into warehouse |
|
|
252
|
+
| `stock_status` | `'available' \| 'quarantined' \| 'expired' \| 'damaged' \| 'reserved'` | **Required.** Current status |
|
|
253
|
+
| `fulfilment_location_id` | `number?` | FK to fulfilment centre |
|
|
254
|
+
| `fulfilment_location_name` | `string?` | Fulfilment centre name |
|
|
255
|
+
| `fulfilment_location_country` | `string?` | ISO country code |
|
|
256
|
+
| `notes` | `string?` | Free-text notes |
|
|
257
|
+
| `created_ts` | `string?` | ISO created timestamp (from BaseEntity) |
|
|
258
|
+
| `updated_ts` | `string?` | ISO updated timestamp (from BaseEntity) |
|
|
259
|
+
|
|
260
|
+
### Location
|
|
261
|
+
|
|
262
|
+
Extends `BaseEntity`.
|
|
263
|
+
|
|
264
|
+
| Field | Type | Description |
|
|
265
|
+
|-------|------|-------------|
|
|
266
|
+
| `id` | `number` | Primary key |
|
|
267
|
+
| `clientId` | `number?` | FK to owning client |
|
|
268
|
+
| `location_code` | `string?` | Unique code (e.g. `"A-01-03-B"`) |
|
|
269
|
+
| `location_type` | `'pick' \| 'bulk' \| 'staging' \| 'receiving' \| 'shipping' \| 'quarantine' \| 'returns'` | **Required.** Location role |
|
|
270
|
+
| `zone` | `string?` | Warehouse zone (e.g. `"A"`) |
|
|
271
|
+
| `aisle` | `string?` | Aisle identifier |
|
|
272
|
+
| `bay` | `string?` | Bay/rack identifier |
|
|
273
|
+
| `level` | `string?` | Vertical level/shelf |
|
|
274
|
+
| `position` | `string?` | Horizontal position |
|
|
275
|
+
| `fulfilment_location_id` | `number?` | FK to fulfilment centre |
|
|
276
|
+
| `fulfilment_location_name` | `string?` | Fulfilment centre name |
|
|
277
|
+
| `current_units` | `number?` | Stock units currently held |
|
|
278
|
+
| `max_capacity_units` | `number?` | Maximum unit capacity |
|
|
279
|
+
| `max_capacity_weight_kg` | `number?` | Maximum weight (kg) |
|
|
280
|
+
| `is_mixed_sku_allowed` | `number?` | 0 = single SKU only, 1 = mixed |
|
|
281
|
+
| `is_active` | `number?` | 0 = decommissioned, 1 = in use |
|
|
282
|
+
| `is_pickable` | `number?` | 0 = no, 1 = yes |
|
|
283
|
+
| `is_receivable` | `number?` | 0 = no, 1 = yes |
|
|
284
|
+
| `temperature_zone` | `'ambient' \| 'chilled' \| 'frozen'` | **Required.** Temperature classification |
|
|
285
|
+
| `notes` | `string?` | Free-text notes |
|
|
286
|
+
|
|
287
|
+
### Invoice
|
|
288
|
+
|
|
289
|
+
Extends `BaseEntity`.
|
|
290
|
+
|
|
291
|
+
| Field | Type | Description |
|
|
292
|
+
|-------|------|-------------|
|
|
293
|
+
| `id` | `number` | Primary key |
|
|
294
|
+
| `clientId` | `number?` | FK to client |
|
|
295
|
+
| `invoice_date` | `string` | **Required.** ISO invoice date |
|
|
296
|
+
| `xero_reference` | `string?` | Xero accounting reference |
|
|
297
|
+
| `total` | `number?` | Total invoice amount |
|
|
298
|
+
| `emailed` | `number?` | 0 = not emailed, 1 = emailed |
|
|
299
|
+
| `paid` | `number?` | 0 = unpaid, 1 = paid |
|
|
300
|
+
| `fuel_mode` | `number?` | 0 = flat rate, 1 = percentage |
|
|
301
|
+
| `status` | `number?` | 0 = inactive/deleted, 1 = active |
|
|
302
|
+
| `invoiceLines` | `InvoiceLine[]?` | Line items |
|
|
303
|
+
|
|
304
|
+
### InvoiceLine
|
|
305
|
+
|
|
306
|
+
Extends `BaseEntity`.
|
|
307
|
+
|
|
308
|
+
| Field | Type | Description |
|
|
309
|
+
|-------|------|-------------|
|
|
310
|
+
| `id` | `number` | Primary key |
|
|
311
|
+
| `invoice_id` | `number?` | FK to parent invoice |
|
|
312
|
+
| `class_id` | `number?` | Charge classification (storage, fulfilment, shipping) |
|
|
313
|
+
| `object_id` | `number?` | FK to billable object (dispatch ID, etc.) |
|
|
314
|
+
| `reference` | `string` | **Required.** Client-facing reference |
|
|
315
|
+
| `description` | `string?` | Charge description |
|
|
316
|
+
| `dispatch_date` | `string?` | ISO dispatch date |
|
|
317
|
+
| `service_name` | `string?` | Shipping service name |
|
|
318
|
+
| `price` | `number?` | Unit price |
|
|
319
|
+
| `discount_rate` | `number?` | Discount percentage |
|
|
320
|
+
| `postcode` | `string?` | Destination postcode |
|
|
321
|
+
| `country_code` | `string?` | ISO destination country |
|
|
322
|
+
| `tax_class` | `number?` | 0 = zero-rated, 1 = standard, 2 = exempt |
|
|
323
|
+
| `consignment_price` | `number?` | Carrier cost before margin |
|
|
324
|
+
| `fuel` | `number?` | Fuel surcharge |
|
|
325
|
+
| `packaging_price` | `number?` | Packaging material cost |
|
|
326
|
+
| `discount` | `number?` | Calculated discount amount |
|
|
327
|
+
| `lines` | `number?` | Number of order lines |
|
|
328
|
+
| `picks` | `number?` | Number of picks |
|
|
329
|
+
| `weight` | `number?` | Total weight (kg) |
|
|
330
|
+
| `margin_charged` | `number?` | Margin on carrier cost |
|
|
331
|
+
| `total_override` | `number?` | Manual total override |
|
|
332
|
+
| `status` | `number?` | 0 = inactive/deleted, 1 = active |
|
|
333
|
+
|
|
334
|
+
### ASN (Advance Shipping Notice)
|
|
335
|
+
|
|
336
|
+
Extends `BaseEntity`.
|
|
337
|
+
|
|
338
|
+
| Field | Type | Description |
|
|
339
|
+
|-------|------|-------------|
|
|
340
|
+
| `id` | `number` | Primary key |
|
|
341
|
+
| `clientId` | `number` | **Required.** FK to client |
|
|
342
|
+
| `asn_status` | `string` | **Required.** One of: `draft`, `awaiting_arrival`, `arrived`, `processing`, `receipted`, `receipted_with_discrepancies`, `temporarily_receipted`, `quarantined`, `cancelled` |
|
|
343
|
+
| `expected_arrival_date` | `string?` | ISO expected arrival date |
|
|
344
|
+
| `total_expected_units` | `number?` | Total expected units |
|
|
345
|
+
| `asnLines` | `AsnLine[]` | Line items |
|
|
346
|
+
|
|
347
|
+
### AsnLine
|
|
348
|
+
|
|
349
|
+
Extends `BaseEntity`.
|
|
350
|
+
|
|
351
|
+
| Field | Type | Description |
|
|
352
|
+
|-------|------|-------------|
|
|
353
|
+
| `id` | `number` | Primary key |
|
|
354
|
+
| `asn_id` | `number` | **Required.** FK to parent ASN |
|
|
355
|
+
| `product_id` | `number?` | FK to product |
|
|
356
|
+
| `sku_code` | `string` | **Required.** SKU code |
|
|
357
|
+
| `expected_quantity` | `number` | **Required.** Expected unit count |
|
|
358
|
+
| `received_quantity` | `number?` | Actual received count |
|
|
359
|
+
| `asnReceipts` | `AsnReceipt[]` | Receipt records |
|
|
360
|
+
|
|
361
|
+
### AsnReceipt
|
|
362
|
+
|
|
363
|
+
Extends `BaseEntity`.
|
|
364
|
+
|
|
365
|
+
| Field | Type | Description |
|
|
366
|
+
|-------|------|-------------|
|
|
367
|
+
| `id` | `number` | Primary key |
|
|
368
|
+
| `asn_id` | `number` | **Required.** FK to ASN |
|
|
369
|
+
| `asn_line_id` | `number` | **Required.** FK to ASN line |
|
|
370
|
+
| `received_quantity` | `number` | **Required.** Quantity received |
|
|
371
|
+
| `stock_status` | `'available' \| 'quarantined' \| 'expired' \| 'damaged' \| 'reserved'` | **Required.** Status of received stock |
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Query Filter Reference
|
|
376
|
+
|
|
377
|
+
### PaginatedQueryFilters (v2 endpoints: products, stocks, locations, invoices, ASNs, dispatches)
|
|
378
|
+
|
|
379
|
+
| Param | Type | Required | Description |
|
|
380
|
+
|-------|------|----------|-------------|
|
|
381
|
+
| `clientId` | `number` | **Yes** | Client ID from `useClient()` |
|
|
382
|
+
| `pageSize` | `number` | No | Results per page (default: 25) |
|
|
383
|
+
| `pageNumber` | `number` | No | Page number, 1-based (default: 1) |
|
|
384
|
+
| `orderColumn` | `string` | No | Column to sort by (e.g. `'id'`, `'created'`) |
|
|
385
|
+
| `orderDirection` | `'ASC' \| 'DESC'` | No | Sort direction (default: DESC) |
|
|
386
|
+
| `query` | `string` | No | Free-text search across key fields |
|
|
387
|
+
|
|
388
|
+
### ReturnsQueryFilters (janus.returns.query)
|
|
389
|
+
|
|
390
|
+
| Param | Type | Required | Description |
|
|
391
|
+
|-------|------|----------|-------------|
|
|
392
|
+
| `clientId` | `number` | **Yes** | Client ID |
|
|
393
|
+
| `page` | `number` | No | Page number |
|
|
394
|
+
| `pageSize` | `number` | No | Results per page |
|
|
395
|
+
| `created_at` | `string` | No | Start date (ISO, e.g. `'2025-01-01'`) |
|
|
396
|
+
| `created_to` | `string` | No | End date (ISO) |
|
|
397
|
+
| `last_status_ids` | `string` | No | Comma-separated status IDs to match current status |
|
|
398
|
+
| `include_status_ids` | `string` | No | Include returns with any of these status IDs |
|
|
399
|
+
| `exclude_status_ids` | `string` | No | Exclude returns with these status IDs |
|
|
400
|
+
| `processed_at` | `string` | No | Processed start date (ISO) |
|
|
401
|
+
| `processed_to` | `string` | No | Processed end date (ISO) |
|
|
402
|
+
| `include_associations` | `string` | No | Nested data: `'return_items'`, `'return_comments'`, or comma-separated |
|
|
403
|
+
| `csv` | `boolean` | No | Export as CSV instead of JSON |
|
|
404
|
+
| `group_by` | `string` | No | Group results by field |
|
|
405
|
+
|
|
406
|
+
### OrdersQueryFilters (janus.orders.getAll)
|
|
407
|
+
|
|
408
|
+
| Param | Type | Required | Description |
|
|
409
|
+
|-------|------|----------|-------------|
|
|
410
|
+
| `clientId` | `number` | **Yes** | Client ID |
|
|
411
|
+
| `page` | `number` | No | Page number |
|
|
412
|
+
| `pageSize` | `number` | No | Results per page |
|
|
413
|
+
| `order_column` | `string` | No | Sort column |
|
|
414
|
+
| `order_direction` | `'ASC' \| 'DESC'` | No | Sort direction |
|
|
415
|
+
| `created_at` | `string` | No | Start date (ISO) |
|
|
416
|
+
| `created_to` | `string` | No | End date (ISO) |
|
|
417
|
+
| `channel` | `string` | No | Filter by sales channel |
|
|
418
|
+
| `destination` | `string` | No | Filter by destination |
|
|
419
|
+
| `courier` | `string` | No | Filter by courier name |
|
|
420
|
+
| `service` | `string` | No | Filter by courier service |
|
|
421
|
+
| `status` | `string` | No | Filter by order status |
|
|
422
|
+
| `query` | `string` | No | Free-text search |
|
|
423
|
+
| `include_all_stages` | `boolean` | No | Include all order stages |
|
|
424
|
+
|
|
425
|
+
### ReturnsSummaryFilters (janus.reports.returnsSummary / returnsSummaryCsv)
|
|
426
|
+
|
|
427
|
+
| Param | Type | Required | Description |
|
|
428
|
+
|-------|------|----------|-------------|
|
|
429
|
+
| `clientId` | `number` | **Yes** | Client ID |
|
|
430
|
+
| `createdFrom` | `string` | No | Start date (ISO) |
|
|
431
|
+
| `createdTo` | `string` | No | End date (ISO) |
|
|
432
|
+
| `approvedFrom` | `string` | No | Approval start date |
|
|
433
|
+
| `approvedTo` | `string` | No | Approval end date |
|
|
434
|
+
| `courierServiceId` | `number` | No | Filter by courier service |
|
|
435
|
+
| `approved` | `boolean` | No | Only approved returns |
|
|
436
|
+
| `isClientsReport` | `boolean` | No | Format as client-level report |
|
|
437
|
+
| `page` | `number` | No | Page number |
|
|
438
|
+
| `pageSize` | `number` | No | Results per page |
|
|
439
|
+
|
|
440
|
+
### ReturnsReasonsFilters (janus.reports.returnsReasons / returnsReasonsCsv)
|
|
441
|
+
|
|
442
|
+
| Param | Type | Required | Description |
|
|
443
|
+
|-------|------|----------|-------------|
|
|
444
|
+
| `clientId` | `number` | **Yes** | Client ID |
|
|
445
|
+
| `createdFrom` | `string` | No | Start date (ISO) |
|
|
446
|
+
| `createdTo` | `string` | No | End date (ISO) |
|
|
447
|
+
|
|
448
|
+
### OrdersStatsFilters (janus.orders.getStats)
|
|
449
|
+
|
|
450
|
+
| Param | Type | Required | Description |
|
|
451
|
+
|-------|------|----------|-------------|
|
|
452
|
+
| `clientId` | `number` | **Yes** | Client ID |
|
|
453
|
+
| `created_at` | `string` | No | Start date (ISO) |
|
|
454
|
+
| `created_to` | `string` | No | End date (ISO) |
|
|
455
|
+
| `dashboard` | `boolean` | No | Return dashboard-formatted stats (recommended: `true`) |
|
|
456
|
+
|
|
457
|
+
### Resource-specific extra filters
|
|
458
|
+
|
|
459
|
+
| Resource method | Extra param | Type | Description |
|
|
460
|
+
|----------------|-----------|------|-------------|
|
|
461
|
+
| `janus.stockTransactions.getAll` | `stockId` | `number` | Filter by stock record |
|
|
462
|
+
| `janus.stockAllocations.getAll` | `orderId` | `number` | Filter by order |
|
|
463
|
+
| `janus.dispatches.getAll` | `orderId` | `number` | Filter by order |
|
|
464
|
+
| `janus.audits.getAll` | `filter` | `string` | Additional filter |
|
|
465
|
+
| `janus.users.getAll` | `filterRole` | `string` | Filter by user role |
|
|
466
|
+
| `janus.users.getAll` | `filterType` | `string` | Filter by user type |
|
|
467
|
+
| `janus.users.getAll` | `filterClientId` | `number` | Filter by assigned client |
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Common Patterns
|
|
472
|
+
|
|
473
|
+
### Querying with Filters and Pagination
|
|
474
|
+
|
|
475
|
+
**v2 endpoints** (products, stocks, locations, invoices, ASNs, dispatches) use `ClientScopedPaginatedQueryFilters`:
|
|
62
476
|
|
|
63
477
|
```typescript
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
|
|
478
|
+
const { data, meta } = await janus.products.getAll({
|
|
479
|
+
clientId: 5, // REQUIRED
|
|
480
|
+
pageSize: 50,
|
|
481
|
+
pageNumber: 1,
|
|
482
|
+
orderColumn: 'sku_code',
|
|
483
|
+
orderDirection: 'ASC',
|
|
484
|
+
query: 'widget', // free-text search
|
|
485
|
+
});
|
|
72
486
|
|
|
73
|
-
//
|
|
74
|
-
const services = await janus.clients.getCourierServices(5);
|
|
75
|
-
const service = await janus.clients.getCourierServiceById(5, serviceId);
|
|
76
|
-
await janus.clients.updateCourierService(5, serviceId, { active: true });
|
|
487
|
+
// meta = { total_items, total_pages, current_page, page_size }
|
|
77
488
|
```
|
|
78
489
|
|
|
79
|
-
|
|
490
|
+
**Legacy endpoints** (orders, returns) use their own filter shapes:
|
|
80
491
|
|
|
81
492
|
```typescript
|
|
82
|
-
// Query returns with filters
|
|
83
493
|
const returns = await janus.returns.query({
|
|
84
494
|
clientId: 5,
|
|
85
495
|
last_status_ids: '1,2,3',
|
|
86
496
|
created_at: '2024-01-01',
|
|
87
497
|
created_to: '2024-12-31',
|
|
88
498
|
pageSize: 100,
|
|
499
|
+
csv: false,
|
|
89
500
|
});
|
|
90
501
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// ...
|
|
502
|
+
const orders = await janus.orders.getAll({
|
|
503
|
+
clientId: 5,
|
|
504
|
+
created_at: '2024-01-01',
|
|
505
|
+
created_to: '2024-12-31',
|
|
506
|
+
status: 'dispatched',
|
|
507
|
+
order_column: 'created',
|
|
508
|
+
order_direction: 'DESC',
|
|
99
509
|
});
|
|
510
|
+
```
|
|
100
511
|
|
|
101
|
-
|
|
102
|
-
await janus.returns.update(123, { customer_name: 'Jane Doe' });
|
|
103
|
-
|
|
104
|
-
// Delete a return
|
|
105
|
-
await janus.returns.delete(123);
|
|
106
|
-
|
|
107
|
-
// Manage statuses
|
|
108
|
-
await janus.returns.addStatus(123, statusId);
|
|
109
|
-
await janus.returns.removeStatus(123, statusId);
|
|
110
|
-
const statuses = await janus.returns.getStatuses(123);
|
|
111
|
-
|
|
112
|
-
// Manage comments
|
|
113
|
-
await janus.returns.addComment(123, 'Comment text');
|
|
114
|
-
await janus.returns.removeComment(123, commentId);
|
|
115
|
-
const comments = await janus.returns.getComments(123);
|
|
116
|
-
|
|
117
|
-
// Manage items
|
|
118
|
-
const items = await janus.returns.getItems(123);
|
|
119
|
-
await janus.returns.addItem(123, { wms_product_sku: 'SKU123', qty: 2 });
|
|
120
|
-
await janus.returns.updateItem(123, itemId, { qty: 3 });
|
|
512
|
+
### CSV Export
|
|
121
513
|
|
|
122
|
-
|
|
123
|
-
await janus.returns.setApproval(123, true); // Approve
|
|
124
|
-
await janus.returns.setApproval(123, false); // Reject
|
|
514
|
+
Reports have dedicated CSV methods:
|
|
125
515
|
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
const
|
|
129
|
-
const
|
|
516
|
+
```typescript
|
|
517
|
+
const csvString = await janus.reports.returnsSummaryCsv({ clientId: 5 });
|
|
518
|
+
const reasonsCsv = await janus.reports.returnsReasonsCsv({ clientId: 5 });
|
|
519
|
+
const overviewCsv = await janus.reports.returnsOverviewCsv({ clientId: 5 });
|
|
130
520
|
```
|
|
131
521
|
|
|
132
|
-
|
|
522
|
+
Returns can also export as CSV via the query filter:
|
|
133
523
|
|
|
134
524
|
```typescript
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
clientId: 5,
|
|
138
|
-
created_at: '2024-01-01',
|
|
139
|
-
created_to: '2024-12-31',
|
|
140
|
-
groupBy: 'month',
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
// CSV export
|
|
144
|
-
const csvData = await janus.reports.returnsSummaryCsv({ clientId: 5 });
|
|
525
|
+
const csv = await janus.returns.query({ clientId: 5, csv: true });
|
|
526
|
+
```
|
|
145
527
|
|
|
146
|
-
|
|
147
|
-
const reasonReport = await janus.reports.returnsReasons({ clientId: 5 });
|
|
148
|
-
const reasonCsv = await janus.reports.returnsReasonsCsv({ clientId: 5 });
|
|
528
|
+
### CRUD on Sub-Resources
|
|
149
529
|
|
|
150
|
-
|
|
151
|
-
const overview = await janus.reports.returnsOverview({ clientId: 5 });
|
|
152
|
-
const overviewCsv = await janus.reports.returnsOverviewCsv({ clientId: 5 });
|
|
530
|
+
Invoices, ASNs, and returns have nested sub-resources:
|
|
153
531
|
|
|
154
|
-
|
|
155
|
-
|
|
532
|
+
```typescript
|
|
533
|
+
// Invoice lines
|
|
534
|
+
const { data: lines } = await janus.invoices.getLines(invoiceId, { clientId: 5 });
|
|
535
|
+
await janus.invoices.createLine(invoiceId, lineData);
|
|
536
|
+
await janus.invoices.updateLine(invoiceId, lineId, updatedData);
|
|
537
|
+
|
|
538
|
+
// ASN lines and receipts
|
|
539
|
+
const { data: asnLines } = await janus.asns.getLines(asnId, { clientId: 5 });
|
|
540
|
+
await janus.asns.createReceipt(asnId, lineId, receiptData);
|
|
541
|
+
|
|
542
|
+
// Return items, comments, statuses
|
|
543
|
+
const items = await janus.returns.getItems(returnId);
|
|
544
|
+
await janus.returns.addComment(returnId, 'Inspected, item damaged');
|
|
545
|
+
await janus.returns.addStatus(returnId, statusId);
|
|
156
546
|
```
|
|
157
547
|
|
|
158
|
-
###
|
|
548
|
+
### Paginated Response Shape
|
|
159
549
|
|
|
160
|
-
|
|
161
|
-
// Submit return portal form (no auth required)
|
|
162
|
-
const result = await janus.helpers.submitReturnPortalForm(formData);
|
|
550
|
+
v2 endpoints return:
|
|
163
551
|
|
|
164
|
-
|
|
165
|
-
|
|
552
|
+
```typescript
|
|
553
|
+
{
|
|
554
|
+
data: T[],
|
|
555
|
+
meta: {
|
|
556
|
+
total_items: number,
|
|
557
|
+
total_pages: number,
|
|
558
|
+
current_page: number,
|
|
559
|
+
page_size: number,
|
|
560
|
+
}
|
|
561
|
+
}
|
|
166
562
|
```
|
|
167
563
|
|
|
168
|
-
|
|
564
|
+
### Raw API Access
|
|
169
565
|
|
|
170
|
-
|
|
566
|
+
For endpoints not yet wrapped:
|
|
171
567
|
|
|
172
568
|
```typescript
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
Return,
|
|
176
|
-
ReturnItem,
|
|
177
|
-
ReturnStatus,
|
|
178
|
-
ReturnReason,
|
|
179
|
-
User,
|
|
180
|
-
// ... more types
|
|
181
|
-
} from '@pelygo/janus';
|
|
569
|
+
const result = await janus.auth.get('/some/endpoint?clientId=5');
|
|
570
|
+
const result = await janus.auth.post('/some/endpoint', { body: 'data' });
|
|
182
571
|
```
|
|
183
572
|
|
|
184
|
-
|
|
573
|
+
---
|
|
185
574
|
|
|
186
|
-
|
|
187
|
-
import type { ReturnsQueryParams, ReportFilters } from '@pelygo/janus';
|
|
575
|
+
## Important Rules
|
|
188
576
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
};
|
|
194
|
-
```
|
|
577
|
+
1. **Always pass `clientId`.**
|
|
578
|
+
Get it from `useClient()` or equivalent. Never omit it.
|
|
579
|
+
- New v2 endpoints (`products`, `stocks`, `locations`, `invoices`, `asns`, `dispatches`) **reject with 400** if `clientId` is missing.
|
|
580
|
+
- Older endpoints (`orders`, `returns`) silently return **all clients' data** if omitted -- this is a data leak, not a feature.
|
|
195
581
|
|
|
196
|
-
|
|
582
|
+
2. **Use the exact field names from this README.**
|
|
583
|
+
Field names differ between entities (e.g. `sku_code` not `sku`, `product_name` not `name`, `price` not `value`). Do not guess -- refer to the tables above.
|
|
197
584
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
585
|
+
3. **Navigation in Base44/iframe environments must use `setTimeout`.**
|
|
586
|
+
Direct `window.location` or router calls inside callbacks (like `onUnauthorized`) will fail silently in iframed environments:
|
|
587
|
+
```typescript
|
|
588
|
+
onUnauthorized: () => {
|
|
589
|
+
setTimeout(() => window.location.href = '/login', 0);
|
|
590
|
+
},
|
|
591
|
+
```
|
|
201
592
|
|
|
202
|
-
|
|
203
|
-
|
|
593
|
+
4. **`baseUrl` and `authUrl` are different servers.**
|
|
594
|
+
Do not pass the same URL for both. The JANUS API server handles data; the auth server handles tokens.
|
|
204
595
|
|
|
205
|
-
|
|
206
|
-
|
|
596
|
+
5. **Use `janus.products` instead of `janus.legacy.queryProducts`.**
|
|
597
|
+
The `products` resource uses the newer v2 endpoint with proper pagination and typed responses.
|
|
207
598
|
|
|
208
|
-
|
|
209
|
-
npm run typecheck
|
|
599
|
+
---
|
|
210
600
|
|
|
211
|
-
|
|
212
|
-
npm run build
|
|
601
|
+
## API Behaviour Notes
|
|
213
602
|
|
|
214
|
-
|
|
215
|
-
|
|
603
|
+
### Error responses
|
|
604
|
+
```json
|
|
605
|
+
{ "statusCode": 400, "message": "Error description" }
|
|
216
606
|
```
|
|
607
|
+
Common codes: 400 (bad request/validation), 401 (unauthorized), 404 (not found).
|
|
217
608
|
|
|
218
|
-
###
|
|
609
|
+
### Date formats
|
|
610
|
+
- **Query params:** ISO 8601 format (`'2025-01-01'` or `'2025-01-01 12:00:00'`)
|
|
611
|
+
- **Response fields:** ISO 8601 timestamps (e.g. `created_ts`, `orderDate`, `created`)
|
|
612
|
+
- **CSV exports:** formatted as `DD-MM-YYYY HH:mm`
|
|
219
613
|
|
|
220
|
-
|
|
614
|
+
### Pagination defaults
|
|
615
|
+
- Default `pageSize`: 50 (v2 endpoints)
|
|
616
|
+
- Default `pageNumber`: 1 (1-based indexing)
|
|
617
|
+
- Default sort: DESC (newest first)
|
|
618
|
+
- Max sensible page size: 1,000
|
|
221
619
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
620
|
+
### Search behaviour (`query` param)
|
|
621
|
+
Free-text search is case-insensitive LIKE matching across key text columns:
|
|
622
|
+
- **Products:** `sku`, `name`, `description`
|
|
623
|
+
- **Returns:** order references, tracking numbers
|
|
624
|
+
- **Clients:** client names
|
|
625
|
+
- **Orders:** order references, channel IDs
|
|
227
626
|
|
|
228
|
-
|
|
229
|
-
|
|
627
|
+
### Returns-specific behaviour
|
|
628
|
+
- **Archived returns** (status ID 10) are excluded by default — pass `include_archived: true` to include
|
|
629
|
+
- **Return types:** `0` = regular return, `1` = exchange — filter with `return_types: '0'` or `'1'`
|
|
630
|
+
- **Associations:** `include_associations: 'return_items'` loads line items; `'return_items,return_comments'` loads both
|
|
631
|
+
- **Approval statuses:** `'pending'`, `'approved'`, `'rejected'`
|
|
230
632
|
|
|
231
|
-
|
|
633
|
+
### Stats responses
|
|
634
|
+
`getStats()` endpoints return flat objects with numeric values. **Keys vary by client data.** Always use `Object.entries(stats)` to iterate — never hardcode expected keys.
|
|
232
635
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
636
|
+
---
|
|
637
|
+
|
|
638
|
+
## Type Imports
|
|
639
|
+
|
|
640
|
+
```typescript
|
|
641
|
+
import type {
|
|
642
|
+
// Entities
|
|
643
|
+
Return, ReturnItem, ReturnStatus, ReturnReason, ReturnComment,
|
|
644
|
+
LegacyOrder, LegacyDispatch, LegacyOrderItem, LegacyDispatchItem,
|
|
645
|
+
LegacyShopperAddress,
|
|
646
|
+
FormattedProduct,
|
|
647
|
+
Stock,
|
|
648
|
+
Location,
|
|
649
|
+
Invoice, InvoiceLine,
|
|
650
|
+
Asn, AsnLine, AsnReceipt,
|
|
651
|
+
Client,
|
|
652
|
+
|
|
653
|
+
// Filters
|
|
654
|
+
ReturnsQueryFilters,
|
|
655
|
+
OrdersQueryFilters,
|
|
656
|
+
ClientScopedPaginatedQueryFilters,
|
|
657
|
+
PaginatedQueryFilters,
|
|
658
|
+
ReturnsSummaryFilters,
|
|
659
|
+
|
|
660
|
+
// Responses
|
|
661
|
+
PaginatedListResponse,
|
|
662
|
+
PaginatedResponse,
|
|
663
|
+
PaginationMeta,
|
|
664
|
+
ReturnsStatsResponse,
|
|
665
|
+
FilterOptionsResponse,
|
|
666
|
+
|
|
667
|
+
// API types
|
|
668
|
+
JanusApi,
|
|
669
|
+
JanusApiOptions,
|
|
670
|
+
} from '@pelygo/janus';
|
|
248
671
|
```
|
|
249
672
|
|
|
250
|
-
|
|
673
|
+
---
|
|
251
674
|
|
|
252
|
-
|
|
675
|
+
## Development
|
|
253
676
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
677
|
+
```bash
|
|
678
|
+
npm run build # Build with Vite
|
|
679
|
+
npm run typecheck # TypeScript check
|
|
680
|
+
npm run test # Run tests with Vitest
|
|
681
|
+
npm run test:run # Run tests once
|
|
682
|
+
npm run generate-types # Generate entity types from v2 TypeORM entities
|
|
683
|
+
```
|
|
257
684
|
|
|
258
685
|
## Related Packages
|
|
259
686
|
|
|
260
|
-
- [@pelygo/auth](https://www.npmjs.com/package/@pelygo/auth)
|
|
687
|
+
- [@pelygo/auth](https://www.npmjs.com/package/@pelygo/auth) -- Authentication client (peer dependency)
|
|
261
688
|
|
|
262
689
|
## License
|
|
263
690
|
|
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
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -2461,9 +2461,24 @@ export declare interface OrdersQueryFilters extends BaseFilters {
|
|
|
2461
2461
|
* Orders resource interface
|
|
2462
2462
|
*/
|
|
2463
2463
|
export declare interface OrdersResource {
|
|
2464
|
-
/**
|
|
2464
|
+
/**
|
|
2465
|
+
* Get all orders with optional query filters (client, date range, status, etc.)
|
|
2466
|
+
*
|
|
2467
|
+
* @example
|
|
2468
|
+
* const orders = await janus.orders.getAll({ clientId, pageSize: 25 });
|
|
2469
|
+
* // Each order has: id, reference, channel, transaction_type, orderDate,
|
|
2470
|
+
* // orderStatus, notes, hold, draft, created, modified,
|
|
2471
|
+
* // orderItems (array), dispatches (array)
|
|
2472
|
+
*/
|
|
2465
2473
|
getAll(filters?: OrdersQueryFilters): Promise<unknown[]>;
|
|
2466
|
-
/**
|
|
2474
|
+
/**
|
|
2475
|
+
* Get aggregated order statistics (counts, totals) with optional filters
|
|
2476
|
+
*
|
|
2477
|
+
* @example
|
|
2478
|
+
* const stats = await janus.orders.getStats({ clientId, dashboard: true });
|
|
2479
|
+
* // Returns a flat object with numeric counts — keys vary by data.
|
|
2480
|
+
* // Use Object.entries(stats) to iterate. Do NOT hardcode field names.
|
|
2481
|
+
*/
|
|
2467
2482
|
getStats(filters?: OrdersStatsFilters): Promise<OrdersStatsResponse>;
|
|
2468
2483
|
/** Get orders that have associated returns, with optional return-specific filters */
|
|
2469
2484
|
getReturns(filters?: OrderReturnsFilters): Promise<unknown[]>;
|
|
@@ -2606,7 +2621,16 @@ export declare interface ProductCategory extends BaseEntity_2 {
|
|
|
2606
2621
|
* Products resource interface
|
|
2607
2622
|
*/
|
|
2608
2623
|
export declare interface ProductsResource {
|
|
2609
|
-
/**
|
|
2624
|
+
/**
|
|
2625
|
+
* Get all products with optional filters
|
|
2626
|
+
*
|
|
2627
|
+
* @example
|
|
2628
|
+
* const { data, meta } = await janus.products.getAll({ clientId, pageSize: 25 });
|
|
2629
|
+
* // Each product has: product_id, client_id, sku_code, product_name,
|
|
2630
|
+
* // description, barcode, price, currency, product_status, stock,
|
|
2631
|
+
* // weight_grams, image_url, product_category_id, created_date, updated_date
|
|
2632
|
+
* // meta has: total_items, total_pages, current_page, page_size
|
|
2633
|
+
*/
|
|
2610
2634
|
getAll(filters: ClientScopedPaginatedQueryFilters): Promise<PaginatedListResponse<FormattedProduct>>;
|
|
2611
2635
|
/** Get a product by ID */
|
|
2612
2636
|
getById(id: number): Promise<FormattedProduct>;
|
|
@@ -2634,7 +2658,14 @@ export declare interface ReportsResource {
|
|
|
2634
2658
|
returnsOverview(filters?: ReturnsOverviewFilters): Promise<unknown>;
|
|
2635
2659
|
/** Get returns overview as CSV */
|
|
2636
2660
|
returnsOverviewCsv(filters?: ReturnsOverviewFilters): Promise<string>;
|
|
2637
|
-
/**
|
|
2661
|
+
/**
|
|
2662
|
+
* Get returns statistics for a client
|
|
2663
|
+
*
|
|
2664
|
+
* @example
|
|
2665
|
+
* const stats = await janus.reports.returnsStats(clientId);
|
|
2666
|
+
* // Returns: { total, awaiting_processing, in_progress, completed,
|
|
2667
|
+
* // awaiting_approval, approved, rejected, by_status, by_reason }
|
|
2668
|
+
*/
|
|
2638
2669
|
returnsStats(clientId: number): Promise<ReturnsStatsResponse>;
|
|
2639
2670
|
}
|
|
2640
2671
|
|
|
@@ -2873,7 +2904,16 @@ export declare interface ReturnsReasonsFilters extends BaseFilters {
|
|
|
2873
2904
|
* Returns resource interface
|
|
2874
2905
|
*/
|
|
2875
2906
|
export declare interface ReturnsResource {
|
|
2876
|
-
/**
|
|
2907
|
+
/**
|
|
2908
|
+
* Query returns with filters
|
|
2909
|
+
*
|
|
2910
|
+
* @example
|
|
2911
|
+
* const returns = await janus.returns.query({ clientId, page: 1, pageSize: 25 });
|
|
2912
|
+
* // Each return has: id, return_reference, wms_order_ref, customername,
|
|
2913
|
+
* // forename, surname, email, approval_status, tracking_number,
|
|
2914
|
+
* // created_ts, updated_ts, latestStatus (object with .name),
|
|
2915
|
+
* // return_items (array, when include_associations set)
|
|
2916
|
+
*/
|
|
2877
2917
|
query(filters?: ReturnsQueryFilters): Promise<Return[]>;
|
|
2878
2918
|
/** Query returns with HTTP query body */
|
|
2879
2919
|
queryPost(query: HttpQueryRequest): Promise<Return[]>;
|
|
@@ -3175,7 +3215,15 @@ export declare interface StockAllocationsResource {
|
|
|
3175
3215
|
* Stocks resource interface
|
|
3176
3216
|
*/
|
|
3177
3217
|
export declare interface StocksResource {
|
|
3178
|
-
/**
|
|
3218
|
+
/**
|
|
3219
|
+
* Get all stock records with optional filters
|
|
3220
|
+
*
|
|
3221
|
+
* @example
|
|
3222
|
+
* const { data, meta } = await janus.stocks.getAll({ clientId, pageSize: 25 });
|
|
3223
|
+
* // Each stock record has: id, clientId, sku_code, location, quantity,
|
|
3224
|
+
* // batch_number, serial_number, best_before_date, stock_status,
|
|
3225
|
+
* // fulfilment_location_id, fulfilment_location_name, notes
|
|
3226
|
+
*/
|
|
3179
3227
|
getAll(filters: ClientScopedPaginatedQueryFilters): Promise<PaginatedListResponse<Stock>>;
|
|
3180
3228
|
/** Get a stock record by ID */
|
|
3181
3229
|
getById(id: number): Promise<Stock>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pelygo/janus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "TypeScript API client for JANUS endpoints with full type safety",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
-
"dist"
|
|
17
|
+
"dist",
|
|
18
|
+
"USAGE.md"
|
|
18
19
|
],
|
|
19
20
|
"scripts": {
|
|
20
21
|
"build": "vite build",
|