@webitel/api-services 26.8.26 → 26.8.28

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/api-services",
3
- "version": "26.8.26",
3
+ "version": "26.8.28",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -50,6 +50,8 @@ export * from './history/transcript/callTranscript';
50
50
  export * from './imClients/imClients';
51
51
  export * from './importTemplates/importTemplates';
52
52
  export * from './labels/labels';
53
+ export * from './license/license';
54
+ export * from './license/licenseUsers';
53
55
  export * from './lists/blacklistNumbers';
54
56
  export * from './lists/blacklists';
55
57
  export * from './logs/logs';
@@ -0,0 +1,93 @@
1
+ import { getCustomers } from '../../../gen-wire';
2
+ import {
3
+ getDefaultGetListResponse,
4
+ getDefaultGetParams,
5
+ getDefaultInstance,
6
+ } from '../../defaults';
7
+ import {
8
+ applyTransform,
9
+ camelToSnake,
10
+ merge,
11
+ mergeEach,
12
+ notify,
13
+ sanitize,
14
+ snakeToCamel,
15
+ starToSearch,
16
+ } from '../../transformers';
17
+ import type { ApiParams } from '../_shared/types';
18
+
19
+ const instance = getDefaultInstance();
20
+
21
+ const getLicenseList = async (params: ApiParams) => {
22
+ const listFieldsToSend = [
23
+ 'page',
24
+ 'size',
25
+ 'q',
26
+ 'sort',
27
+ 'fields',
28
+ 'id',
29
+ ];
30
+
31
+ const defaultObject = {
32
+ remain: 0,
33
+ limit: 0,
34
+ };
35
+
36
+ const requestParams = applyTransform(params, [
37
+ merge(getDefaultGetParams()),
38
+ starToSearch('search'),
39
+ starToSearch('q'),
40
+ (params: ApiParams) => ({
41
+ ...params,
42
+ // filtersManager may pass `q` (Path A) or legacy `search`
43
+ q: params.q ?? params.search,
44
+ // wire declares repeated `sort` (`string[]`); datalist sends a string
45
+ sort: params.sort
46
+ ? [
47
+ params.sort,
48
+ ]
49
+ : undefined,
50
+ }),
51
+ sanitize(listFieldsToSend),
52
+ camelToSnake(),
53
+ ]);
54
+
55
+ try {
56
+ const response = await getCustomers().licenseUsage2(requestParams);
57
+ const { items, next } = applyTransform(response.data, [
58
+ snakeToCamel(),
59
+ merge(getDefaultGetListResponse()),
60
+ ]);
61
+ return {
62
+ items: applyTransform(items, [
63
+ mergeEach(defaultObject),
64
+ ]),
65
+ next,
66
+ };
67
+ } catch (err) {
68
+ throw applyTransform(err, [
69
+ notify,
70
+ ]);
71
+ }
72
+ };
73
+
74
+ /**
75
+ * Import / update customer certificate.
76
+ * Sent as JSON body — matches admin's historical contract. Generated
77
+ * `updateCustomer` puts `certificate` in query params with an empty body.
78
+ */
79
+ const updateLicense = async (data: { certificate: string }) => {
80
+ try {
81
+ const response = await instance.put('/customer', data);
82
+ return applyTransform(response.data, []);
83
+ } catch (err) {
84
+ throw applyTransform(err, [
85
+ notify,
86
+ ]);
87
+ }
88
+ };
89
+
90
+ export const LicenseAPI = {
91
+ getList: getLicenseList,
92
+ update: updateLicense,
93
+ };
@@ -0,0 +1,80 @@
1
+ import { getCustomers } from '../../../gen-wire';
2
+ import { getDefaultGetListResponse, getDefaultGetParams } from '../../defaults';
3
+ import {
4
+ applyTransform,
5
+ camelToSnake,
6
+ merge,
7
+ mergeEach,
8
+ notify,
9
+ sanitize,
10
+ snakeToCamel,
11
+ starToSearch,
12
+ } from '../../transformers';
13
+ import type { ApiId, ApiParams } from '../_shared/types';
14
+
15
+ const getLicenseUsersList = async ({
16
+ parentId,
17
+ ...rest
18
+ }: {
19
+ parentId: ApiId;
20
+ } & ApiParams) => {
21
+ const listFieldsToSend = [
22
+ 'page',
23
+ 'size',
24
+ 'q',
25
+ 'sort',
26
+ 'fields',
27
+ 'id',
28
+ ];
29
+
30
+ const defaultObject = {
31
+ sessions: 0,
32
+ };
33
+
34
+ const requestParams = applyTransform(rest, [
35
+ merge(getDefaultGetParams()),
36
+ starToSearch('search'),
37
+ starToSearch('q'),
38
+ (params: ApiParams) => ({
39
+ ...params,
40
+ q: params.q ?? params.search,
41
+ // Product-users select rejects `id` — ui-datalist may still put it in `fields`
42
+ fields: Array.isArray(params.fields)
43
+ ? params.fields.filter((field: string) => field !== 'id')
44
+ : params.fields,
45
+ // wire declares repeated `sort` (`string[]`); datalist sends a string
46
+ sort: params.sort
47
+ ? [
48
+ params.sort,
49
+ ]
50
+ : undefined,
51
+ }),
52
+ sanitize(listFieldsToSend),
53
+ camelToSnake(),
54
+ ]);
55
+
56
+ try {
57
+ const response = await getCustomers().licenseUsers(
58
+ String(parentId),
59
+ requestParams,
60
+ );
61
+ const { items, next } = applyTransform(response.data, [
62
+ snakeToCamel(),
63
+ merge(getDefaultGetListResponse()),
64
+ ]);
65
+ return {
66
+ items: applyTransform(items, [
67
+ mergeEach(defaultObject),
68
+ ]),
69
+ next,
70
+ };
71
+ } catch (err) {
72
+ throw applyTransform(err, [
73
+ notify,
74
+ ]);
75
+ }
76
+ };
77
+
78
+ export const LicenseUsersAPI = {
79
+ getList: getLicenseUsersList,
80
+ };
@@ -1,3 +1,4 @@
1
+ import { getDefaultsFromZodSchema } from '@webitel/api-services/gen/utils';
1
2
  import { describe, expect, it } from 'vitest';
2
3
  import type { z } from 'zod';
3
4
  import {
@@ -602,6 +603,41 @@ describe('calendarSchema', () => {
602
603
 
603
604
  expect(result.success).toBe(true);
604
605
  });
606
+
607
+ /** [WTEL-10431](https://webitel.atlassian.net/browse/WTEL-10431) */
608
+ it('defaults both ends to the current day when omitted', () => {
609
+ const before = Date.now();
610
+ const result = calendarSchema.parse(minimalValidInput);
611
+ const after = Date.now();
612
+
613
+ expect(result.startAt).toBeGreaterThanOrEqual(before);
614
+ expect(result.startAt).toBeLessThanOrEqual(after);
615
+ expect(result.endAt).toBeGreaterThanOrEqual(before);
616
+ expect(result.endAt).toBeLessThanOrEqual(after);
617
+ });
618
+
619
+ /** an empty draft still seeds the pickers, even though `name` is missing */
620
+ it('seeds a blank draft with the current day', () => {
621
+ const before = Date.now();
622
+ const result = getDefaultsFromZodSchema(calendarSchema, {}) as {
623
+ startAt: number;
624
+ endAt: number;
625
+ };
626
+
627
+ expect(result.startAt).toBeGreaterThanOrEqual(before);
628
+ expect(result.endAt).toBeGreaterThanOrEqual(before);
629
+ });
630
+
631
+ it('keeps a null explicitly set on the draft', () => {
632
+ const result = calendarSchema.parse({
633
+ ...minimalValidInput,
634
+ startAt: null,
635
+ endAt: null,
636
+ });
637
+
638
+ expect(result.startAt).toBeNull();
639
+ expect(result.endAt).toBeNull();
640
+ });
605
641
  });
606
642
 
607
643
  describe('negative cases', () => {
@@ -195,6 +195,15 @@ const defaultSpecials = () =>
195
195
  }),
196
196
  );
197
197
 
198
+ /**
199
+ * A new temporary calendar opens on the current day: the `expires` switcher
200
+ * reveals the pickers already filled, instead of two empty required-looking
201
+ * fields. Matches the same fallback the API mapper applies to a stored calendar.
202
+ *
203
+ * [WTEL-10431](https://webitel.atlassian.net/browse/WTEL-10431)
204
+ */
205
+ const today = () => Date.now();
206
+
198
207
  export const calendarSchema = z.object<
199
208
  ZodShape<EngineCalendar> & {
200
209
  expires?: z.ZodType;
@@ -205,8 +214,8 @@ export const calendarSchema = z.object<
205
214
  name: z.string().min(1),
206
215
  description: z.string().optional().default(''),
207
216
  timezone: requiredLookupSchema,
208
- startAt: z.any().optional(),
209
- endAt: z.any().optional(),
217
+ startAt: z.any().optional().default(today),
218
+ endAt: z.any().optional().default(today),
210
219
  expires: z.boolean().optional().default(false),
211
220
  accepts: acceptsOfDayUiArraySchema.default(defaultAccepts),
212
221
  specials: acceptsOfDayUiArraySchema.default(defaultSpecials),
@@ -24,6 +24,7 @@ export * from './contactGroup/contactGroup.validations';
24
24
  export * from './contactGroupCondition/contactGroupCondition.validations';
25
25
  export * from './contactPhone/contactPhone.validations';
26
26
  export * from './device/device.validations';
27
+ export * from './license/licenseImport.validations';
27
28
  export * from './OAuth/OAuth.validations';
28
29
  export * from './onlineSkill/onlineSkill.validations';
29
30
  export * from './queue/queue.rules';
@@ -0,0 +1,11 @@
1
+ import type { UpdateCustomerParams } from '@webitel/api-services/gen/models';
2
+ import { z } from 'zod';
3
+
4
+ import type { ZodShape } from '../types';
5
+
6
+ /** Payload for importing a license certificate via `PUT /customer`. */
7
+ export const licenseImportSchema = z.object<
8
+ ZodShape<Pick<UpdateCustomerParams, 'certificate'>>
9
+ >({
10
+ certificate: z.string().min(1).default(''),
11
+ });