repzo 1.0.289 → 1.0.290

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.
@@ -0,0 +1,272 @@
1
+ openapi: 3.0.3
2
+ info:
3
+ title: Repzo API - Bulk Export
4
+ version: 1.0.0
5
+ description: |
6
+ Exports large datasets to **Excel** or **Parquet**. Starting an export
7
+ (`POST /bulk-export`) creates a job for one of ~50 supported entity types
8
+ (`clients`, `products`, `contracts`, `reps`, ...) selected via the `type`
9
+ query parameter; the job runs the aggregation, writes the file to media
10
+ storage, and records a `status` and a download `link`. `GET /bulk-export`
11
+ lists the export jobs (see also `bulk-export-report`).
12
+
13
+ **Who calls it.** Back-office admins — the `creator` audit stamp is always
14
+ an admin, set server-side from the session token.
15
+
16
+ **Multi-tenancy & lifecycle.** Jobs are scoped by `company_namespace[]`
17
+ (injected from session — never sent in the body). A job moves through
18
+ `processing` then `success` / `fail`; on success, `link` (and the `media`
19
+ storage id) point at the generated file.
20
+
21
+ **Unsupported operations.** Only find (list jobs) and create (start a job)
22
+ are available. `GET /bulk-export/{id}`, `update`, `patch`, and `remove` are
23
+ rejected with `400`.
24
+ servers:
25
+ - url: https://sv.api.repzo.me
26
+ security:
27
+ - ApiKeyAuth: []
28
+ - JwtAuth: []
29
+ paths:
30
+ /bulk-export:
31
+ get:
32
+ summary: List bulk-export jobs
33
+ operationId: findBulkExports
34
+ parameters:
35
+ - in: query
36
+ name: _id
37
+ description: Filter by job `_id`. Pass once or as `?_id[]=...` for multiple.
38
+ schema:
39
+ oneOf:
40
+ - type: string
41
+ - type: array
42
+ items: { type: string }
43
+ - in: query
44
+ name: type
45
+ description: Filter by exported entity type.
46
+ schema:
47
+ $ref: "#/components/schemas/BulkExportType"
48
+ - in: query
49
+ name: status
50
+ description: Filter by job status.
51
+ schema:
52
+ type: string
53
+ enum: [processing, success, fail]
54
+ - in: query
55
+ name: export_type
56
+ description: Filter by output format.
57
+ schema:
58
+ type: string
59
+ enum: [excel, parquet]
60
+ - in: query
61
+ name: export
62
+ description: When truthy, schedule the export as an emailed job instead of returning it inline.
63
+ schema: { type: boolean }
64
+ - in: query
65
+ name: from_updatedAt
66
+ description: Cursor — jobs updated on or after this Unix timestamp (ms).
67
+ schema: { type: number }
68
+ - in: query
69
+ name: to_updatedAt
70
+ description: Cursor — jobs updated on or before this Unix timestamp (ms).
71
+ schema: { type: number }
72
+ - in: query
73
+ name: per_page
74
+ schema: { type: integer, minimum: 1, maximum: 50000 }
75
+ example: 20
76
+ - in: query
77
+ name: page
78
+ schema: { type: integer, minimum: 1 }
79
+ example: 1
80
+ responses:
81
+ "200":
82
+ description: A paginated list of export jobs.
83
+ content:
84
+ application/json:
85
+ schema:
86
+ $ref: "#/components/schemas/BulkExportFindResult"
87
+ post:
88
+ summary: Start a bulk export
89
+ operationId: createBulkExport
90
+ parameters:
91
+ - in: query
92
+ name: type
93
+ required: true
94
+ description: Entity type to export. Sent as a query parameter, not in the body.
95
+ schema:
96
+ $ref: "#/components/schemas/BulkExportType"
97
+ requestBody:
98
+ required: true
99
+ content:
100
+ application/json:
101
+ schema:
102
+ $ref: "#/components/schemas/BulkExportCreateBody"
103
+ responses:
104
+ "201":
105
+ description: The created export job — `status` reflects progress and `link` is populated when the file is ready.
106
+ content:
107
+ application/json:
108
+ schema:
109
+ $ref: "#/components/schemas/BulkExportSchema"
110
+ components:
111
+ securitySchemes:
112
+ ApiKeyAuth:
113
+ type: apiKey
114
+ in: header
115
+ name: api-key
116
+ description: |
117
+ Server-issued API key. Also accepted via the `x-api-key` header or the
118
+ `?apiKey=` query parameter as fallbacks.
119
+ JwtAuth:
120
+ type: apiKey
121
+ in: header
122
+ name: Authorization
123
+ description: |
124
+ Raw JWT in the `Authorization` header — **no `Bearer ` prefix**. Obtained
125
+ from `POST /authenticate` (admin login).
126
+ schemas:
127
+ BulkExportType:
128
+ type: string
129
+ description: One of the supported export entity types.
130
+ enum:
131
+ - clients
132
+ - products
133
+ - variants
134
+ - categories
135
+ - subCategories
136
+ - availabilityMsl
137
+ - availabilityMslWithProducts
138
+ - reps
139
+ - mslWithVariants
140
+ - jobCategories
141
+ - jobs
142
+ - tags
143
+ - routes
144
+ - routesWithClients
145
+ - plans
146
+ - planWithRules
147
+ - targetRulesWithClients
148
+ - rulesWithRoutes
149
+ - targetRulesWithReps
150
+ - adjustAccount
151
+ - rules
152
+ - warehouses
153
+ - productGroups
154
+ - priceListItems
155
+ - measureunit
156
+ - measureunitFamily
157
+ - lineTarget
158
+ - clientLineClassification
159
+ - retailExecutionPresets
160
+ - promotions
161
+ - customListItems
162
+ - assets
163
+ - assetUnits
164
+ - speciality
165
+ - clientLocation
166
+ - reminders
167
+ - admins
168
+ - companyGroup
169
+ - company
170
+ - variantBatch
171
+ - banksList
172
+ - clientUblInfo
173
+ - supplier
174
+ - contractInstallment
175
+ - targetRule
176
+ - contracts
177
+ - assetPartTypes
178
+ - assetParts
179
+ - clientUblInfo_JO
180
+ - clientUblInfo_SA
181
+ - nameSpaceFreshnessWindowCodes
182
+ BulkExportCreateBody:
183
+ type: object
184
+ description: |
185
+ Export options. `type` is sent as a query parameter (not in the body).
186
+ The `creator` audit stamp and `company_namespace` are normally injected
187
+ from session and can be omitted — both are optional here for
188
+ integration / cross-namespace callers.
189
+ properties:
190
+ export_type:
191
+ type: string
192
+ enum: [excel, parquet]
193
+ default: excel
194
+ columns:
195
+ type: object
196
+ additionalProperties: true
197
+ description: Map of column paths to include / label in the generated file.
198
+ name:
199
+ type: string
200
+ description: Optional label for the export job.
201
+ creator:
202
+ $ref: "#/components/schemas/BulkExportCreator"
203
+ company_namespace:
204
+ type: array
205
+ items: { type: string }
206
+ description: Tenant key — normally injected from session; optional, for cross-namespace callers.
207
+ BulkExportCreator:
208
+ type: object
209
+ description: Audit stamp of the admin who started the job. Set server-side from the session token — never sent by the client.
210
+ properties:
211
+ _id: { type: string }
212
+ type: { type: string, enum: [admin] }
213
+ name: { type: string }
214
+ admin: { type: string }
215
+ BulkExportSchema:
216
+ type: object
217
+ description: A bulk-export job document as stored.
218
+ properties:
219
+ _id: { type: string }
220
+ creator:
221
+ $ref: "#/components/schemas/BulkExportCreator"
222
+ type:
223
+ $ref: "#/components/schemas/BulkExportType"
224
+ status:
225
+ type: string
226
+ enum: [processing, success, fail]
227
+ messages:
228
+ type: array
229
+ items: { type: object }
230
+ _errors:
231
+ type: array
232
+ items: { type: object }
233
+ start_time: { type: integer, format: int64 }
234
+ end_time: { type: integer, format: int64 }
235
+ bucket_name: { type: string }
236
+ region: { type: string }
237
+ key: { type: string }
238
+ link: { type: string, description: Download URL of the generated file. }
239
+ media:
240
+ type: array
241
+ items: { type: string }
242
+ description: "Media-storage `_id`(s) of the generated file (ref `media-storage`)."
243
+ teams:
244
+ type: array
245
+ items: { type: string }
246
+ export_type:
247
+ type: string
248
+ enum: [excel, parquet]
249
+ row_count: { type: number }
250
+ company_namespace:
251
+ type: array
252
+ items: { type: string }
253
+ createdAt: { type: string, format: date-time }
254
+ updatedAt: { type: string, format: date-time }
255
+ BulkExportFindResult:
256
+ type: object
257
+ description: Paginated list of export jobs.
258
+ properties:
259
+ data:
260
+ type: array
261
+ items:
262
+ $ref: "#/components/schemas/BulkExportSchema"
263
+ total_result: { type: number }
264
+ current_count: { type: number }
265
+ total_pages: { type: number }
266
+ current_page: { type: number }
267
+ per_page: { type: number }
268
+ first_page_url: { type: string }
269
+ last_page_url: { type: string }
270
+ next_page_url: { type: string, nullable: true }
271
+ prev_page_url: { type: string, nullable: true }
272
+ path: { type: string }
@@ -0,0 +1,349 @@
1
+ openapi: 3.0.3
2
+ info:
3
+ title: Repzo API - Geo Zone
4
+ version: 1.0.0
5
+ description: |
6
+ A **Geo Zone** is a named geographic area defined by a single GeoJSON
7
+ polygon. Zones are assigned to reps (via the rep's `assigned_geo_zones`
8
+ array — currently capped at one zone per rep) so the mobile app can
9
+ enforce location policies — e.g. whether a rep may start the day or
10
+ start a visit while outside their zone.
11
+
12
+ **Who uses it.** Admins manage zones from the back office and assign
13
+ them through the `rep` service. The mobile app reads zones (with the
14
+ incremental `from_updatedAt` cursor) to evaluate policies offline.
15
+
16
+ **Multi-tenancy & lifecycle.** Records are scoped by
17
+ `company_namespace[]` (injected from session — never sent in the body)
18
+ and use **soft-delete** via `disabled: true`. `name` is unique per
19
+ namespace among non-deleted zones. A zone that is still assigned to one
20
+ or more reps **cannot be disabled or deleted** — the request is rejected
21
+ with `400` naming the assigned reps; reassign them first.
22
+
23
+ **Validation.** A zone cannot be saved without a `name` and a valid
24
+ polygon: the polygon needs at least one closed linear ring of 4+
25
+ `[longitude, latitude]` positions (first and last must match, longitude
26
+ in ±180, latitude in ±90). Violations return a `400` naming the failing
27
+ ring.
28
+
29
+ **Key relationships.** Referenced by `rep.assigned_geo_zones`. The
30
+ `editor` audit object (who created / last updated the zone) is stamped
31
+ server-side from the session token.
32
+ servers:
33
+ - url: https://sv.api.repzo.me
34
+ security:
35
+ - ApiKeyAuth: []
36
+ - JwtAuth: []
37
+ paths:
38
+ /geo-zone:
39
+ get:
40
+ summary: Find geo zones
41
+ operationId: findGeoZones
42
+ parameters:
43
+ - in: query
44
+ name: _id
45
+ description: Filter by zone `_id`. Pass once or as `?_id[]=...` for multiple.
46
+ schema:
47
+ oneOf:
48
+ - type: string
49
+ - type: array
50
+ items: { type: string }
51
+ - in: query
52
+ name: name
53
+ description: Exact-match on zone name. Pass once or as `?name[]=...` for multiple.
54
+ schema:
55
+ oneOf:
56
+ - type: string
57
+ - type: array
58
+ items: { type: string }
59
+ - in: query
60
+ name: search
61
+ description: Case-insensitive substring search on `name`.
62
+ schema: { type: string }
63
+ example: north
64
+ - in: query
65
+ name: disabled
66
+ description: Include disabled (soft-deleted) zones. Defaults to `false`.
67
+ schema: { type: boolean, default: false }
68
+ - in: query
69
+ name: inject_assigned_reps
70
+ description: |
71
+ When truthy, each returned zone is enriched with an
72
+ `assigned_reps[]` array (`_id`, `name`) of the active reps whose
73
+ `assigned_geo_zones` contains it.
74
+ schema: { type: boolean, default: false }
75
+ - in: query
76
+ name: from_updatedAt
77
+ description: Cursor — zones updated on or after this Unix timestamp (ms). Used by the mobile app for incremental sync.
78
+ schema: { type: number }
79
+ - in: query
80
+ name: to_updatedAt
81
+ description: Cursor — zones updated on or before this Unix timestamp (ms).
82
+ schema: { type: number }
83
+ - in: query
84
+ name: from_createdAt
85
+ description: Cursor — zones created on or after this Unix timestamp (ms).
86
+ schema: { type: number }
87
+ - in: query
88
+ name: to_createdAt
89
+ description: Cursor — zones created on or before this Unix timestamp (ms).
90
+ schema: { type: number }
91
+ - in: query
92
+ name: per_page
93
+ description: Page size. Defaults to the server's configured pagination limit.
94
+ schema: { type: integer, minimum: 1, maximum: 500 }
95
+ example: 50
96
+ - in: query
97
+ name: page
98
+ description: 1-indexed page number.
99
+ schema: { type: integer, minimum: 1 }
100
+ example: 1
101
+ responses:
102
+ "200":
103
+ description: A paginated list of geo zones matching the filter.
104
+ content:
105
+ application/json:
106
+ schema:
107
+ $ref: "#/components/schemas/GeoZoneFindResult"
108
+ post:
109
+ summary: Create a geo zone
110
+ operationId: createGeoZone
111
+ requestBody:
112
+ required: true
113
+ content:
114
+ application/json:
115
+ schema:
116
+ $ref: "#/components/schemas/GeoZoneCreateBody"
117
+ responses:
118
+ "201":
119
+ description: The newly-created geo zone. `editor` is stamped from the session token.
120
+ content:
121
+ application/json:
122
+ schema:
123
+ $ref: "#/components/schemas/GeoZoneSchema"
124
+ "400":
125
+ description: |
126
+ Validation failure — missing `name`, missing polygon, or an
127
+ invalid polygon (open ring, fewer than 4 positions, out-of-range
128
+ coordinates). The message names the failing ring. Also returned
129
+ when the zone name already exists in the namespace.
130
+ /geo-zone/{id}:
131
+ get:
132
+ summary: Get a geo zone by ID
133
+ operationId: getGeoZone
134
+ parameters:
135
+ - in: path
136
+ name: id
137
+ required: true
138
+ schema: { type: string }
139
+ - in: query
140
+ name: inject_assigned_reps
141
+ description: When truthy, the zone is enriched with an `assigned_reps[]` array (`_id`, `name`).
142
+ schema: { type: boolean, default: false }
143
+ responses:
144
+ "200":
145
+ description: The geo zone document for the given `_id`.
146
+ content:
147
+ application/json:
148
+ schema:
149
+ $ref: "#/components/schemas/GeoZoneSchema"
150
+ put:
151
+ summary: Update a geo zone
152
+ operationId: updateGeoZone
153
+ description: |
154
+ Partial update — only the fields present in the body are changed.
155
+ `polygon`, when sent, replaces the zone's polygon and is validated
156
+ like create. Setting `disabled: true` deactivates the zone and is
157
+ **rejected with `400` while any rep is still assigned to it**;
158
+ reassign those reps first.
159
+ parameters:
160
+ - in: path
161
+ name: id
162
+ required: true
163
+ schema: { type: string }
164
+ requestBody:
165
+ required: true
166
+ content:
167
+ application/json:
168
+ schema:
169
+ $ref: "#/components/schemas/GeoZoneUpdateBody"
170
+ responses:
171
+ "200":
172
+ description: The geo zone document after the update is applied.
173
+ content:
174
+ application/json:
175
+ schema:
176
+ $ref: "#/components/schemas/GeoZoneSchema"
177
+ "400":
178
+ description: Zone not found, polygon validation failure, or the zone is being disabled while reps are still assigned to it.
179
+ delete:
180
+ summary: Remove a geo zone (soft-delete)
181
+ operationId: removeGeoZone
182
+ description: |
183
+ Soft-deletes the zone (`disabled: true`). Rejected with `400` while
184
+ any rep is still assigned to it — the error names the assigned reps;
185
+ reassign them to another zone first.
186
+ parameters:
187
+ - in: path
188
+ name: id
189
+ required: true
190
+ schema: { type: string }
191
+ responses:
192
+ "200":
193
+ description: "The geo zone document after soft-deletion (`disabled: true`)."
194
+ content:
195
+ application/json:
196
+ schema:
197
+ $ref: "#/components/schemas/GeoZoneSchema"
198
+ "400":
199
+ description: Zone not found, or the zone is still assigned to one or more reps.
200
+ components:
201
+ securitySchemes:
202
+ ApiKeyAuth:
203
+ type: apiKey
204
+ in: header
205
+ name: api-key
206
+ description: |
207
+ Server-issued API key. Also accepted via the `x-api-key` header or the
208
+ `?apiKey=` query parameter as fallbacks.
209
+ JwtAuth:
210
+ type: apiKey
211
+ in: header
212
+ name: Authorization
213
+ description: |
214
+ Raw JWT in the `Authorization` header — **no `Bearer ` prefix**. Obtained from
215
+ `POST /authenticate` (admin / rep / client login).
216
+ schemas:
217
+ GeoZoneFindResult:
218
+ type: object
219
+ description: Paginated list of geo zones.
220
+ properties:
221
+ data:
222
+ type: array
223
+ items:
224
+ $ref: "#/components/schemas/GeoZoneSchema"
225
+ total_result: { type: number }
226
+ current_count: { type: number }
227
+ total_pages: { type: number }
228
+ current_page: { type: number }
229
+ per_page: { type: number }
230
+ first_page_url: { type: string }
231
+ last_page_url: { type: string }
232
+ next_page_url: { type: string, nullable: true }
233
+ prev_page_url: { type: string, nullable: true }
234
+ path: { type: string }
235
+ GeoZoneSchema:
236
+ type: object
237
+ description: Geo zone document as stored.
238
+ properties:
239
+ _id: { type: string }
240
+ name:
241
+ {
242
+ type: string,
243
+ description: Unique per namespace among non-deleted zones.,
244
+ }
245
+ description: { type: string }
246
+ polygon:
247
+ $ref: "#/components/schemas/GeoZonePolygon"
248
+ disabled:
249
+ { type: boolean, description: Soft-delete / deactivation flag. }
250
+ editor:
251
+ $ref: "#/components/schemas/GeoZoneEditor"
252
+ assigned_reps:
253
+ type: array
254
+ description: "Present only when the request sent `inject_assigned_reps=true` — the active reps assigned to this zone."
255
+ items:
256
+ type: object
257
+ properties:
258
+ _id: { type: string }
259
+ name: { type: string }
260
+ company_namespace:
261
+ type: array
262
+ items: { type: string }
263
+ description: Tenant key set on save from session.
264
+ createdAt: { type: string, format: date-time }
265
+ updatedAt: { type: string, format: date-time }
266
+ __v: { type: number }
267
+ GeoZonePolygon:
268
+ type: object
269
+ description: |
270
+ A GeoJSON Polygon. `coordinates` is an array of linear rings; the
271
+ first ring is the outer boundary, any further rings are holes.
272
+ required: [coordinates]
273
+ properties:
274
+ type:
275
+ type: string
276
+ enum: [Polygon]
277
+ default: Polygon
278
+ coordinates:
279
+ type: array
280
+ minItems: 1
281
+ description: |
282
+ Array of linear rings. Each ring is an array of at least 4
283
+ positions and must be closed (first position equals the last).
284
+ Positions are ordered as **longitude, latitude** (longitude
285
+ first) — longitude in [-180, 180], latitude in [-90, 90].
286
+ items:
287
+ type: array
288
+ minItems: 4
289
+ description: "A closed linear ring of `[longitude, latitude]` positions."
290
+ items:
291
+ type: array
292
+ minItems: 2
293
+ maxItems: 2
294
+ items: { type: number }
295
+ example:
296
+ - - [35.910, 31.954]
297
+ - [35.930, 31.954]
298
+ - [35.930, 31.970]
299
+ - [35.910, 31.954]
300
+ GeoZoneEditor:
301
+ type: object
302
+ description: Audit stamp of who created / last updated the zone. Set server-side from the session token — never sent by the client.
303
+ properties:
304
+ _id: { type: string }
305
+ type: { type: string, enum: [admin, rep, tenant, client] }
306
+ name: { type: string }
307
+ rep: { type: string }
308
+ admin: { type: string }
309
+ client: { type: string }
310
+ tenant: { type: string }
311
+ GeoZoneCreateBody:
312
+ type: object
313
+ description: |
314
+ Body for creating a geo zone. The `editor` audit stamp is stamped
315
+ server-side from the session token (not accepted on create). The tenant
316
+ key (`company_namespace`) is normally injected from session and can be
317
+ omitted — it is optional here for integration / cross-namespace callers.
318
+ The soft-delete flag (`disabled`) defaults to `false`.
319
+ required:
320
+ - name
321
+ - polygon
322
+ properties:
323
+ name:
324
+ type: string
325
+ description: Zone name — required and unique per namespace among non-deleted zones.
326
+ description: { type: string }
327
+ polygon:
328
+ $ref: "#/components/schemas/GeoZonePolygon"
329
+ company_namespace:
330
+ type: array
331
+ items: { type: string }
332
+ description: Tenant key — normally injected from session; optional, for cross-namespace callers.
333
+ GeoZoneUpdateBody:
334
+ type: object
335
+ description: |
336
+ Body for updating a geo zone — only the fields present are changed.
337
+ The tenant key (`company_namespace`) is derived from session. The
338
+ `editor` audit stamp is normally refreshed server-side but may be
339
+ provided (optional).
340
+ properties:
341
+ name: { type: string }
342
+ description: { type: string }
343
+ polygon:
344
+ $ref: "#/components/schemas/GeoZonePolygon"
345
+ disabled:
346
+ type: boolean
347
+ description: "Soft-delete / deactivation flag. Setting `true` is rejected while any rep is still assigned to this zone."
348
+ editor:
349
+ $ref: "#/components/schemas/GeoZoneEditor"