@ikatec/digisac-api-sdk 4.15.0 → 4.17.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 +3 -1
- package/dist/apis/absence/AbsenceApi.cjs +2 -2
- package/dist/apis/absence/AbsenceApi.cjs.map +1 -1
- package/dist/apis/absence/AbsenceApi.d.ts +2 -2
- package/dist/apis/absence/AbsenceApi.mjs +2 -2
- package/dist/apis/absence/AbsenceApi.mjs.map +1 -1
- package/dist/apis/absence/types.d.ts +1 -1
- package/dist/apis/answers/AnswersApi.cjs +23 -2
- package/dist/apis/answers/AnswersApi.cjs.map +1 -1
- package/dist/apis/answers/AnswersApi.d.ts +16 -2
- package/dist/apis/answers/AnswersApi.d.ts.map +1 -1
- package/dist/apis/answers/AnswersApi.mjs +23 -2
- package/dist/apis/answers/AnswersApi.mjs.map +1 -1
- package/dist/apis/answers/types.d.ts +1 -2
- package/dist/apis/answers/types.d.ts.map +1 -1
- package/dist/apis/bots/BotsApi.cjs +16 -7
- package/dist/apis/bots/BotsApi.cjs.map +1 -1
- package/dist/apis/bots/BotsApi.d.ts +13 -7
- package/dist/apis/bots/BotsApi.d.ts.map +1 -1
- package/dist/apis/bots/BotsApi.mjs +16 -7
- package/dist/apis/bots/BotsApi.mjs.map +1 -1
- package/dist/apis/bots/types.d.ts +12 -2
- package/dist/apis/bots/types.d.ts.map +1 -1
- package/dist/apis/campaigns/CampaignsApi.cjs +25 -1
- package/dist/apis/campaigns/CampaignsApi.cjs.map +1 -1
- package/dist/apis/campaigns/CampaignsApi.d.ts +16 -1
- package/dist/apis/campaigns/CampaignsApi.d.ts.map +1 -1
- package/dist/apis/campaigns/CampaignsApi.mjs +25 -1
- package/dist/apis/campaigns/CampaignsApi.mjs.map +1 -1
- package/dist/apis/campaigns/types.d.ts +98 -6
- package/dist/apis/campaigns/types.d.ts.map +1 -1
- package/dist/apis/cards/types.d.ts +5 -5
- package/dist/apis/categories/CategoriesApi.cjs +1 -2
- package/dist/apis/categories/CategoriesApi.cjs.map +1 -1
- package/dist/apis/categories/CategoriesApi.d.ts +1 -2
- package/dist/apis/categories/CategoriesApi.d.ts.map +1 -1
- package/dist/apis/categories/CategoriesApi.mjs +1 -2
- package/dist/apis/categories/CategoriesApi.mjs.map +1 -1
- package/dist/apis/clientFeedback/ClientFeedbackApi.cjs +2 -3
- package/dist/apis/clientFeedback/ClientFeedbackApi.cjs.map +1 -1
- package/dist/apis/clientFeedback/ClientFeedbackApi.d.ts +2 -3
- package/dist/apis/clientFeedback/ClientFeedbackApi.d.ts.map +1 -1
- package/dist/apis/clientFeedback/ClientFeedbackApi.mjs +2 -3
- package/dist/apis/clientFeedback/ClientFeedbackApi.mjs.map +1 -1
- package/dist/apis/contacts/ContactsApi.cjs +10 -6
- package/dist/apis/contacts/ContactsApi.cjs.map +1 -1
- package/dist/apis/contacts/ContactsApi.d.ts +19 -3
- package/dist/apis/contacts/ContactsApi.d.ts.map +1 -1
- package/dist/apis/contacts/ContactsApi.mjs +10 -6
- package/dist/apis/contacts/ContactsApi.mjs.map +1 -1
- package/dist/apis/contacts/types.d.ts +25 -0
- package/dist/apis/contacts/types.d.ts.map +1 -1
- package/dist/apis/customFields/types.d.ts +4 -4
- package/dist/apis/dashboard/DashboardApi.cjs +3 -3
- package/dist/apis/dashboard/DashboardApi.cjs.map +1 -1
- package/dist/apis/dashboard/DashboardApi.d.ts +3 -3
- package/dist/apis/dashboard/DashboardApi.mjs +3 -3
- package/dist/apis/dashboard/DashboardApi.mjs.map +1 -1
- package/dist/apis/dashboard/types.d.ts +11 -4
- package/dist/apis/dashboard/types.d.ts.map +1 -1
- package/dist/apis/departments/DepartmentsApi.cjs +5 -5
- package/dist/apis/departments/DepartmentsApi.cjs.map +1 -1
- package/dist/apis/departments/DepartmentsApi.d.ts +5 -5
- package/dist/apis/departments/DepartmentsApi.mjs +5 -5
- package/dist/apis/departments/DepartmentsApi.mjs.map +1 -1
- package/dist/apis/departments/types.d.ts +6 -0
- package/dist/apis/departments/types.d.ts.map +1 -1
- package/dist/apis/distribution/DistributionApi.cjs +3 -4
- package/dist/apis/distribution/DistributionApi.cjs.map +1 -1
- package/dist/apis/distribution/DistributionApi.d.ts +3 -4
- package/dist/apis/distribution/DistributionApi.d.ts.map +1 -1
- package/dist/apis/distribution/DistributionApi.mjs +3 -4
- package/dist/apis/distribution/DistributionApi.mjs.map +1 -1
- package/dist/apis/kanbanCards/KanbanCardsApi.cjs +32 -0
- package/dist/apis/kanbanCards/KanbanCardsApi.cjs.map +1 -1
- package/dist/apis/kanbanCards/KanbanCardsApi.d.ts +27 -1
- package/dist/apis/kanbanCards/KanbanCardsApi.d.ts.map +1 -1
- package/dist/apis/kanbanCards/KanbanCardsApi.mjs +32 -0
- package/dist/apis/kanbanCards/KanbanCardsApi.mjs.map +1 -1
- package/dist/apis/kanbanCards/types.d.ts +1 -1
- package/dist/apis/kanbanCards/types.d.ts.map +1 -1
- package/dist/apis/kanbanColumns/KanbanColumnsApi.cjs +19 -0
- package/dist/apis/kanbanColumns/KanbanColumnsApi.cjs.map +1 -1
- package/dist/apis/kanbanColumns/KanbanColumnsApi.d.ts +16 -1
- package/dist/apis/kanbanColumns/KanbanColumnsApi.d.ts.map +1 -1
- package/dist/apis/kanbanColumns/KanbanColumnsApi.mjs +19 -0
- package/dist/apis/kanbanColumns/KanbanColumnsApi.mjs.map +1 -1
- package/dist/apis/kanbanColumns/types.d.ts +4 -0
- package/dist/apis/kanbanColumns/types.d.ts.map +1 -1
- package/dist/apis/messages/MessagesApi.cjs +13 -4
- package/dist/apis/messages/MessagesApi.cjs.map +1 -1
- package/dist/apis/messages/MessagesApi.d.ts +13 -4
- package/dist/apis/messages/MessagesApi.d.ts.map +1 -1
- package/dist/apis/messages/MessagesApi.mjs +13 -4
- package/dist/apis/messages/MessagesApi.mjs.map +1 -1
- package/dist/apis/messages/types.d.ts +30 -0
- package/dist/apis/messages/types.d.ts.map +1 -1
- package/dist/apis/pipeline/types.d.ts +7 -8
- package/dist/apis/pipeline/types.d.ts.map +1 -1
- package/dist/apis/quickReplies/types.d.ts +4 -1
- package/dist/apis/quickReplies/types.d.ts.map +1 -1
- package/dist/apis/schedule/types.d.ts +41 -10
- package/dist/apis/schedule/types.d.ts.map +1 -1
- package/dist/apis/terms/TermsApi.cjs +2 -2
- package/dist/apis/terms/TermsApi.cjs.map +1 -1
- package/dist/apis/terms/TermsApi.d.ts +2 -2
- package/dist/apis/terms/TermsApi.mjs +2 -2
- package/dist/apis/terms/TermsApi.mjs.map +1 -1
- package/dist/apis/tickets/TicketsApi.cjs +18 -8
- package/dist/apis/tickets/TicketsApi.cjs.map +1 -1
- package/dist/apis/tickets/TicketsApi.d.ts +15 -8
- package/dist/apis/tickets/TicketsApi.d.ts.map +1 -1
- package/dist/apis/tickets/TicketsApi.mjs +18 -8
- package/dist/apis/tickets/TicketsApi.mjs.map +1 -1
- package/dist/apis/tickets/types.d.ts +4 -1
- package/dist/apis/tickets/types.d.ts.map +1 -1
- package/dist/apis/timetable/TimetableApi.cjs +6 -0
- package/dist/apis/timetable/TimetableApi.cjs.map +1 -1
- package/dist/apis/timetable/TimetableApi.d.ts +6 -0
- package/dist/apis/timetable/TimetableApi.d.ts.map +1 -1
- package/dist/apis/timetable/TimetableApi.mjs +6 -0
- package/dist/apis/timetable/TimetableApi.mjs.map +1 -1
- package/dist/apis/timetable/types.d.ts +8 -0
- package/dist/apis/timetable/types.d.ts.map +1 -1
- package/dist/apis/users/UsersApi.cjs +11 -3
- package/dist/apis/users/UsersApi.cjs.map +1 -1
- package/dist/apis/users/UsersApi.d.ts +10 -4
- package/dist/apis/users/UsersApi.d.ts.map +1 -1
- package/dist/apis/users/UsersApi.mjs +11 -3
- package/dist/apis/users/UsersApi.mjs.map +1 -1
- package/dist/apis/users/types.d.ts +26 -0
- package/dist/apis/users/types.d.ts.map +1 -1
- package/dist/apis/webhooks/types.d.ts +51 -6
- package/dist/apis/webhooks/types.d.ts.map +1 -1
- package/dist/core/errors.cjs +4 -1
- package/dist/core/errors.cjs.map +1 -1
- package/dist/core/errors.d.ts +4 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.mjs +4 -1
- package/dist/core/errors.mjs.map +1 -1
- package/package.json +1 -1
- package/src/apis/absence/AbsenceApi.ts +2 -2
- package/src/apis/absence/types.ts +1 -1
- package/src/apis/answers/AnswersApi.test.ts +32 -0
- package/src/apis/answers/AnswersApi.ts +38 -2
- package/src/apis/answers/types.ts +1 -2
- package/src/apis/bots/BotsApi.test.ts +16 -0
- package/src/apis/bots/BotsApi.ts +25 -7
- package/src/apis/bots/types.ts +12 -2
- package/src/apis/campaigns/CampaignsApi.test.ts +48 -0
- package/src/apis/campaigns/CampaignsApi.ts +31 -2
- package/src/apis/campaigns/types.ts +101 -3
- package/src/apis/cards/types.ts +5 -5
- package/src/apis/categories/CategoriesApi.ts +1 -2
- package/src/apis/clientFeedback/ClientFeedbackApi.ts +2 -3
- package/src/apis/contacts/ContactsApi.test.ts +36 -2
- package/src/apis/contacts/ContactsApi.ts +41 -3
- package/src/apis/contacts/types.ts +28 -0
- package/src/apis/creditMovements/CreditMovementsApi.test.ts +1 -1
- package/src/apis/customFields/types.ts +4 -4
- package/src/apis/dashboard/DashboardApi.test-d.ts +9 -0
- package/src/apis/dashboard/DashboardApi.ts +3 -3
- package/src/apis/dashboard/types.ts +11 -4
- package/src/apis/departments/DepartmentsApi.ts +5 -5
- package/src/apis/departments/types.ts +13 -0
- package/src/apis/distribution/DistributionApi.ts +3 -4
- package/src/apis/kanbanCards/KanbanCardsApi.test.ts +21 -0
- package/src/apis/kanbanCards/KanbanCardsApi.ts +47 -1
- package/src/apis/kanbanCards/types.ts +1 -1
- package/src/apis/kanbanColumns/KanbanColumnsApi.test.ts +26 -0
- package/src/apis/kanbanColumns/KanbanColumnsApi.ts +31 -0
- package/src/apis/kanbanColumns/types.ts +5 -0
- package/src/apis/messages/MessagesApi.ts +13 -4
- package/src/apis/messages/types.ts +31 -0
- package/src/apis/payloads.test-d.ts +217 -4
- package/src/apis/pipeline/types.ts +7 -8
- package/src/apis/queryFormat.test.ts +13 -0
- package/src/apis/quickReplies/types.ts +4 -1
- package/src/apis/schedule/types.ts +42 -10
- package/src/apis/terms/TermsApi.ts +2 -2
- package/src/apis/tickets/TicketsApi.ts +28 -8
- package/src/apis/tickets/types.ts +4 -1
- package/src/apis/timetable/TimetableApi.ts +6 -0
- package/src/apis/timetable/types.ts +9 -0
- package/src/apis/users/UsersApi.test.ts +17 -0
- package/src/apis/users/UsersApi.ts +21 -3
- package/src/apis/users/types.ts +28 -0
- package/src/apis/webhooks/types.ts +53 -6
- package/src/core/errors.ts +4 -1
|
@@ -34,6 +34,8 @@ export type CampaignConfig = {
|
|
|
34
34
|
nameField?: string
|
|
35
35
|
/** Column name in the import file used as the phone number. */
|
|
36
36
|
numberField?: string
|
|
37
|
+
/** Column name in the import file used as the username (contacts known only by it). */
|
|
38
|
+
usernameField?: string
|
|
37
39
|
delimiter?: ',' | ';' | ':' | string
|
|
38
40
|
error?: {
|
|
39
41
|
message: string
|
|
@@ -65,7 +67,10 @@ export type Campaign = {
|
|
|
65
67
|
marketingIntegration?: boolean
|
|
66
68
|
/** Always `null`: the campaign has no such column (answered by the transformer). */
|
|
67
69
|
userId?: null
|
|
68
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* In the pages of `getMany` (not with `paginate: false`) and in `getOne`: messages sent and
|
|
72
|
+
* viewed (ack 3).
|
|
73
|
+
*/
|
|
69
74
|
stats?: { sent: number; viewed: number }
|
|
70
75
|
accountId: string
|
|
71
76
|
serviceId: string
|
|
@@ -116,9 +121,21 @@ export type CampaignRelationships =
|
|
|
116
121
|
| 'messages'
|
|
117
122
|
| 'importFile'
|
|
118
123
|
|
|
124
|
+
/** The media of a header parameter of the template (send it as `{ link: '<url>' }`). */
|
|
125
|
+
export type CampaignTemplateMedia = {
|
|
126
|
+
link?: string
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* A parameter of the template: `text`, or the media of its `type` (`image`, `video` or
|
|
131
|
+
* `document`).
|
|
132
|
+
*/
|
|
119
133
|
export type CampaignTemplateParameterItem = {
|
|
120
134
|
type: string
|
|
121
135
|
text?: string
|
|
136
|
+
image?: CampaignTemplateMedia
|
|
137
|
+
video?: CampaignTemplateMedia
|
|
138
|
+
document?: CampaignTemplateMedia
|
|
122
139
|
}
|
|
123
140
|
|
|
124
141
|
export type CampaignTemplateParameter = {
|
|
@@ -135,30 +152,111 @@ export type CampaignFileTemplate = {
|
|
|
135
152
|
name?: string
|
|
136
153
|
}
|
|
137
154
|
|
|
155
|
+
/** A message of the campaign to create (without `hsm`, the campaign sends these). */
|
|
156
|
+
export type CampaignMessageInput = {
|
|
157
|
+
text?: string
|
|
158
|
+
/** The attachment of the message, as a data URL (`data:<mimetype>;base64,<content>`). */
|
|
159
|
+
base64Url?: string
|
|
160
|
+
/** @deprecated Ignored by the backend: send the attachment as `base64Url`. */
|
|
161
|
+
fileId?: string
|
|
162
|
+
}
|
|
163
|
+
|
|
138
164
|
export type CreateCampaignPayload = {
|
|
139
165
|
title: string
|
|
140
166
|
serviceId: string
|
|
141
167
|
config?: { minInterval: number | string; maxInterval: number | string }
|
|
142
168
|
tagIds?: string[]
|
|
143
|
-
messages?:
|
|
169
|
+
messages?: CampaignMessageInput[]
|
|
170
|
+
/** On create, replaces the `text` of every message (and is the text of the template message). */
|
|
171
|
+
text?: string
|
|
144
172
|
isScheduled?: boolean
|
|
145
173
|
sendsAt?: string | null
|
|
146
174
|
mustOpenTicket?: boolean
|
|
147
175
|
defaultDepartmentId?: string | null
|
|
148
176
|
defaultUserId?: string | null
|
|
177
|
+
/** @deprecated Ignored by the backend: the contacts come from `tagIds` or the import `fileId`. */
|
|
149
178
|
contacts?: Record<string, string>[]
|
|
179
|
+
/** @deprecated Ignored by the backend: the contacts come from `tagIds` or the import `fileId`. */
|
|
150
180
|
useTags?: boolean
|
|
181
|
+
/**
|
|
182
|
+
* On create, the import file (CSV) of the contacts, uploaded with
|
|
183
|
+
* `attachedType: 'campaign.file'`. The columns are read by `nameField`, `numberField` and
|
|
184
|
+
* `usernameField`.
|
|
185
|
+
*/
|
|
151
186
|
fileId?: string
|
|
187
|
+
/** On create, stored in `config.nameField` (a `config.nameField` sent here is replaced). */
|
|
152
188
|
nameField?: string
|
|
189
|
+
/** On create, stored in `config.numberField` (a `config.numberField` sent here is replaced). */
|
|
153
190
|
numberField?: string
|
|
191
|
+
/** Stored in `config.usernameField` (a `config.usernameField` sent here is replaced). */
|
|
192
|
+
usernameField?: string
|
|
154
193
|
// whatsapp-business specific
|
|
194
|
+
/**
|
|
195
|
+
* The template to send. On create, the campaign gets one message of it and `messages` is not
|
|
196
|
+
* read.
|
|
197
|
+
*/
|
|
155
198
|
hsm?: WhatsappBusinessTemplate
|
|
156
199
|
parameters?: CampaignTemplateParameter[]
|
|
200
|
+
/**
|
|
201
|
+
* The header file of the template message (only with `hsm`), already uploaded. Takes precedence
|
|
202
|
+
* over `fileTemplate`.
|
|
203
|
+
*/
|
|
204
|
+
hsmFileId?: string
|
|
205
|
+
/**
|
|
206
|
+
* The header media of the template message: `base64Url` as a data URL, with its `mimetype`
|
|
207
|
+
* (required on create) and `name`. On create, read only when `tagIds` is sent (an empty array is
|
|
208
|
+
* enough); with the import `fileId`, prefer `hsmFileId`. On update, it only replaces the header
|
|
209
|
+
* file the template message already has: send it only with a new data URL, and leave it out to
|
|
210
|
+
* keep the header.
|
|
211
|
+
*/
|
|
157
212
|
fileTemplate?: CampaignFileTemplate
|
|
158
213
|
marketingIntegration?: boolean
|
|
159
214
|
}
|
|
160
215
|
|
|
161
|
-
|
|
216
|
+
/**
|
|
217
|
+
* A message of `updateById`. With the `id` of an existing message, the message gets the `text`
|
|
218
|
+
* sent; without `id`, it is created (and `base64Url` is read as in the create).
|
|
219
|
+
*/
|
|
220
|
+
export type UpdateCampaignMessageInput = CampaignMessageInput & {
|
|
221
|
+
id?: string
|
|
222
|
+
/**
|
|
223
|
+
* On WhatsApp connections, keeps the attachment of an existing message (send the `file` of the
|
|
224
|
+
* message read); with `file`, `base64Url` is not read. Without `file` and `base64Url`, the
|
|
225
|
+
* attachment is removed.
|
|
226
|
+
*/
|
|
227
|
+
file?: unknown
|
|
228
|
+
/**
|
|
229
|
+
* On WhatsApp connections, the name of the new attachment in `base64Url`: to replace the
|
|
230
|
+
* attachment of an existing message, send `base64Url` with a new name and without `file`.
|
|
231
|
+
*/
|
|
232
|
+
fileName?: string
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* `updateById` (`PUT`). A non-empty `messages` replaces the messages: the ones with the `id` of an
|
|
237
|
+
* existing message update it, the ones without `id` are created and the existing ones left out are
|
|
238
|
+
* deleted (omitted, or `[]`, keeps them).
|
|
239
|
+
*
|
|
240
|
+
* Send `isScheduled` (with `sendsAt`) and `mustOpenTicket` (with `defaultDepartmentId` and
|
|
241
|
+
* `defaultUserId`) on every call: without `isScheduled: true`, `sendsAt` is stored as `null` and a
|
|
242
|
+
* scheduled campaign is no longer started at the date; without `mustOpenTicket: true`, the default
|
|
243
|
+
* department and user are cleared.
|
|
244
|
+
*
|
|
245
|
+
* On WhatsApp Business connections, send the existing message by its `id` (a message without `id`
|
|
246
|
+
* is created without the template), together with `hsm` and `parameters`: every update that sends
|
|
247
|
+
* `messages` or `hsm` rewrites both on the existing messages (a missing one is stored empty).
|
|
248
|
+
*/
|
|
249
|
+
export type UpdateCampaignPayload = Omit<
|
|
250
|
+
Partial<CreateCampaignPayload>,
|
|
251
|
+
'text' | 'usernameField' | 'hsmFileId' | 'messages' | 'config'
|
|
252
|
+
> & {
|
|
253
|
+
/**
|
|
254
|
+
* Replaces the stored config as a whole. `minInterval` and `maxInterval` go as strings (a number
|
|
255
|
+
* answers 400).
|
|
256
|
+
*/
|
|
257
|
+
config?: { minInterval: number | string; maxInterval: number | string }
|
|
258
|
+
messages?: UpdateCampaignMessageInput[]
|
|
259
|
+
}
|
|
162
260
|
|
|
163
261
|
/** The visible states the `status` filter of `getMany` takes (`'scheduled'` is derived from `isScheduled` + `sendsAt`). */
|
|
164
262
|
export type CampaignListStatus = CampaignStatus | 'scheduled'
|
package/src/apis/cards/types.ts
CHANGED
|
@@ -182,8 +182,8 @@ export type BulkMoveCardsPayload = {
|
|
|
182
182
|
export type BulkMoveCardsResult = { movedCount: number; ignoredCount: number }
|
|
183
183
|
|
|
184
184
|
/**
|
|
185
|
-
* Creates a product of a card, or updates the product of `id`.
|
|
186
|
-
* a missing
|
|
185
|
+
* Creates a product of a card, or updates the product of `id`. `name`, `ammount` and `value` are
|
|
186
|
+
* required (a missing one answers 500).
|
|
187
187
|
*/
|
|
188
188
|
export type SaveCardProductPayload = {
|
|
189
189
|
id?: string
|
|
@@ -218,9 +218,9 @@ export type CardOwner = {
|
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
/**
|
|
221
|
-
* Body of `POST /cards/getCards`:
|
|
222
|
-
*
|
|
223
|
-
*
|
|
221
|
+
* Body of `POST /cards/getCards`: a list query of the cards. Send `where.accountId` with the id of
|
|
222
|
+
* the current account (`accountId` of `MeApi.getMe`). `order` accepts card fields and
|
|
223
|
+
* `contact.name`.
|
|
224
224
|
*/
|
|
225
225
|
export type GetCardsPayload = Omit<
|
|
226
226
|
ListQuery<Card>,
|
|
@@ -15,8 +15,7 @@ export class CategoriesApi extends BaseCrudApi<
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Deletes a category. Resolves the text `'OK'`; an unknown id answers 500.
|
|
19
|
-
* permission.
|
|
18
|
+
* Deletes a category. Resolves the text `'OK'`; an unknown id answers 500.
|
|
20
19
|
*/
|
|
21
20
|
override deleteById(id: string, headers?: Record<string, string>): Promise<'OK'> {
|
|
22
21
|
return super.deleteById(id, headers)
|
|
@@ -9,9 +9,8 @@ export class ClientFeedbackApi
|
|
|
9
9
|
private readonly basePath = '/client-feedback'
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* @deprecated The route is
|
|
13
|
-
*
|
|
14
|
-
* feedback on the AI summary is stored when the ticket is closed.
|
|
12
|
+
* @deprecated The route is not available (it answers 500). Send the rating of the AI summary
|
|
13
|
+
* when closing the ticket: `ContactsApi.closeTicket` with `aiSummaryRating`.
|
|
15
14
|
*/
|
|
16
15
|
create(
|
|
17
16
|
body: CreateClientFeedbackPayload,
|
|
@@ -365,14 +365,26 @@ describe('ContactsApi', () => {
|
|
|
365
365
|
|
|
366
366
|
describe('transferTicket', () => {
|
|
367
367
|
it('calls client.post with /contacts/:id/ticket/transfer and payload', async () => {
|
|
368
|
-
vi.mocked(client.post).mockResolvedValue(
|
|
368
|
+
vi.mocked(client.post).mockResolvedValue(true)
|
|
369
369
|
const result = await api.transferTicket('c1', { departmentId: 'd1' })
|
|
370
370
|
expect(client.post).toHaveBeenCalledWith(
|
|
371
371
|
'/contacts/c1/ticket/transfer',
|
|
372
372
|
{ departmentId: 'd1' },
|
|
373
373
|
undefined,
|
|
374
374
|
)
|
|
375
|
-
expect(result).
|
|
375
|
+
expect(result).toBe(true)
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
it('sends includeKanbanCardId and resolves the id of the card', async () => {
|
|
379
|
+
vi.mocked(client.post).mockResolvedValue({ kanbanCardId: 'kc1' })
|
|
380
|
+
const payload = {
|
|
381
|
+
departmentId: 'd1',
|
|
382
|
+
kanbanCardColumnId: 'col1',
|
|
383
|
+
includeKanbanCardId: true,
|
|
384
|
+
} as const
|
|
385
|
+
const result = await api.transferTicket('c1', payload)
|
|
386
|
+
expect(client.post).toHaveBeenCalledWith('/contacts/c1/ticket/transfer', payload, undefined)
|
|
387
|
+
expect(result.kanbanCardId).toBe('kc1')
|
|
376
388
|
})
|
|
377
389
|
|
|
378
390
|
it('includes optional userId and forwards custom headers', async () => {
|
|
@@ -387,6 +399,28 @@ describe('ContactsApi', () => {
|
|
|
387
399
|
})
|
|
388
400
|
})
|
|
389
401
|
|
|
402
|
+
// ── closeTicket ──────────────────────────────────────────────────
|
|
403
|
+
|
|
404
|
+
describe('closeTicket', () => {
|
|
405
|
+
it('calls client.post with /contacts/:id/ticket/close and an empty body by default', async () => {
|
|
406
|
+
vi.mocked(client.post).mockResolvedValue(true)
|
|
407
|
+
expect(await api.closeTicket('c1')).toBe(true)
|
|
408
|
+
expect(client.post).toHaveBeenCalledWith('/contacts/c1/ticket/close', {}, undefined)
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
it('sends the subjects, the comment and the rating of the AI summary', async () => {
|
|
412
|
+
vi.mocked(client.post).mockResolvedValue(true)
|
|
413
|
+
const headers = { 'X-Custom': 'h' }
|
|
414
|
+
const payload = {
|
|
415
|
+
ticketTopicIds: ['tt1'],
|
|
416
|
+
comments: 'Resolvido',
|
|
417
|
+
aiSummaryRating: '5' as const,
|
|
418
|
+
}
|
|
419
|
+
await api.closeTicket('c1', payload, headers)
|
|
420
|
+
expect(client.post).toHaveBeenCalledWith('/contacts/c1/ticket/close', payload, headers)
|
|
421
|
+
})
|
|
422
|
+
})
|
|
423
|
+
|
|
390
424
|
// ── createMany ───────────────────────────────────────────────────
|
|
391
425
|
|
|
392
426
|
describe('createMany', () => {
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
BlockContactPayload,
|
|
7
7
|
BulkTransferTicketsPayload,
|
|
8
8
|
BulkTransferTicketsResult,
|
|
9
|
+
CloseTicketPayload,
|
|
9
10
|
Contact,
|
|
10
11
|
ContactGetByIdQuery,
|
|
11
12
|
ContactListQuery,
|
|
@@ -21,6 +22,7 @@ import type {
|
|
|
21
22
|
ExportTemplatePayload,
|
|
22
23
|
ImportContactsPayload,
|
|
23
24
|
SyncContactPayload,
|
|
25
|
+
TransferTicketKanbanCardResult,
|
|
24
26
|
TransferTicketPayload,
|
|
25
27
|
UpdateContactPayload,
|
|
26
28
|
SummarizeTicketResult,
|
|
@@ -141,20 +143,56 @@ export class ContactsApi extends BaseCrudApi<
|
|
|
141
143
|
/**
|
|
142
144
|
* Opens (or transfers) the contact's ticket to a department, and optionally a user.
|
|
143
145
|
* This is the real ticket-open flow used by the UI — there is no `POST /tickets`.
|
|
146
|
+
* Resolves `true`, or `{ kanbanCardId }` with `includeKanbanCardId: true`. When the current
|
|
147
|
+
* ticket of the contact is already closed, the call only releases it and opens nothing: call it
|
|
148
|
+
* again to open a ticket.
|
|
144
149
|
* @permissions tickets.transfer.all OR tickets.transfer.me
|
|
145
150
|
*/
|
|
151
|
+
transferTicket(
|
|
152
|
+
contactId: string,
|
|
153
|
+
payload: TransferTicketPayload & { includeKanbanCardId: true },
|
|
154
|
+
headers?: Record<string, string>,
|
|
155
|
+
): Promise<TransferTicketKanbanCardResult>
|
|
156
|
+
transferTicket(
|
|
157
|
+
contactId: string,
|
|
158
|
+
payload: TransferTicketPayload & { includeKanbanCardId?: false },
|
|
159
|
+
headers?: Record<string, string>,
|
|
160
|
+
): Promise<true>
|
|
161
|
+
transferTicket(
|
|
162
|
+
contactId: string,
|
|
163
|
+
payload: TransferTicketPayload,
|
|
164
|
+
headers?: Record<string, string>,
|
|
165
|
+
): Promise<true | TransferTicketKanbanCardResult>
|
|
146
166
|
transferTicket(
|
|
147
167
|
contactId: string,
|
|
148
168
|
payload: TransferTicketPayload,
|
|
149
169
|
headers?: Record<string, string>,
|
|
150
|
-
): Promise<
|
|
151
|
-
return this.client.post<
|
|
170
|
+
): Promise<true | TransferTicketKanbanCardResult> {
|
|
171
|
+
return this.client.post<true | TransferTicketKanbanCardResult, TransferTicketPayload>(
|
|
152
172
|
`${this.basePath}/${contactId}/ticket/transfer`,
|
|
153
173
|
payload,
|
|
154
174
|
headers,
|
|
155
175
|
)
|
|
156
176
|
}
|
|
157
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Closes the open ticket of the contact and resolves `true`. A contact without an open ticket
|
|
180
|
+
* answers 500, or `true` (closing nothing) when its current ticket is already closed. An unknown
|
|
181
|
+
* subject in `ticketTopicIds`, or one of another department, answers 400.
|
|
182
|
+
* @permissions tickets.close.me OR tickets.close.all
|
|
183
|
+
*/
|
|
184
|
+
closeTicket(
|
|
185
|
+
contactId: string,
|
|
186
|
+
payload: CloseTicketPayload = {},
|
|
187
|
+
headers?: Record<string, string>,
|
|
188
|
+
): Promise<true> {
|
|
189
|
+
return this.client.post<true, CloseTicketPayload>(
|
|
190
|
+
`${this.basePath}/${contactId}/ticket/close`,
|
|
191
|
+
payload,
|
|
192
|
+
headers,
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
|
|
158
196
|
/**
|
|
159
197
|
* Creates or updates several contacts in one call. Existing contacts (same service and
|
|
160
198
|
* number or e-mail) are updated; the others are created. Returns the resulting contacts.
|
|
@@ -226,7 +264,7 @@ export class ContactsApi extends BaseCrudApi<
|
|
|
226
264
|
/**
|
|
227
265
|
* Blocks or unblocks a contact. Blocking closes the contact's open ticket. Requires the
|
|
228
266
|
* block list to be active on the account (`settings.isBlockListActive`; 400 otherwise).
|
|
229
|
-
* `byUserId`
|
|
267
|
+
* Send `byUserId` with the logged user (`id` of `MeApi.getMe`), as the web app does.
|
|
230
268
|
* @permissions contacts.block
|
|
231
269
|
*/
|
|
232
270
|
block(id: string, body: BlockContactPayload, headers?: Record<string, string>): Promise<Contact> {
|
|
@@ -291,6 +291,34 @@ export type TransferTicketPayload = {
|
|
|
291
291
|
kanbanCardColumnId?: string
|
|
292
292
|
kanbanCardSubject?: string
|
|
293
293
|
initialMessage?: string
|
|
294
|
+
/** `true` (the boolean) resolves the id of the kanban card instead of `true`. */
|
|
295
|
+
includeKanbanCardId?: boolean
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** What `ContactsApi.transferTicket` resolves to with `includeKanbanCardId: true`. */
|
|
299
|
+
export type TransferTicketKanbanCardResult = {
|
|
300
|
+
/**
|
|
301
|
+
* The kanban card of the ticket (created, or the contact's card moved, in `kanbanCardColumnId`);
|
|
302
|
+
* `null` without `kanbanCardColumnId` (even when the ticket gets a card in the initial column of
|
|
303
|
+
* the board: send `kanbanCardColumnId` to read its id), when the department has no board, or when
|
|
304
|
+
* the call only released a closed ticket.
|
|
305
|
+
*/
|
|
306
|
+
kanbanCardId: string | null
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** The rating of the AI summary of the ticket. */
|
|
310
|
+
export type AiSummaryRating = '1' | '2' | '3' | '4' | '5'
|
|
311
|
+
|
|
312
|
+
export type CloseTicketPayload = {
|
|
313
|
+
/**
|
|
314
|
+
* Subjects of the ticket: of its department, or linked to no department. An unknown subject, or
|
|
315
|
+
* one of another department, answers 400.
|
|
316
|
+
*/
|
|
317
|
+
ticketTopicIds?: string[]
|
|
318
|
+
/** The closing comment. */
|
|
319
|
+
comments?: string
|
|
320
|
+
/** Stored as the feedback of the AI summary of the ticket. */
|
|
321
|
+
aiSummaryRating?: AiSummaryRating
|
|
294
322
|
}
|
|
295
323
|
|
|
296
324
|
/**
|
|
@@ -83,6 +83,6 @@ describe('CreditMovementsApi', () => {
|
|
|
83
83
|
const withoutRaw: ApiClient = { ...client, requestRaw: undefined }
|
|
84
84
|
await expect(
|
|
85
85
|
new CreditMovementsApi(withoutRaw).exportXlsx({ from: 'a', to: 'b', where: { $and: [] } }),
|
|
86
|
-
).rejects.toThrow('requestRaw')
|
|
86
|
+
).rejects.toThrow('exportXlsx needs a client with requestRaw')
|
|
87
87
|
})
|
|
88
88
|
})
|
|
@@ -22,10 +22,10 @@ export type CustomFieldOption = {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Settings of a custom field
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* `
|
|
25
|
+
* Settings of a custom field (a free JSON object, answered as stored). The fields below are the
|
|
26
|
+
* ones the web app form sends: `options` for the `list` and `checkbox` types, `min`/`max` for
|
|
27
|
+
* `numeric` and `monetary`, `currency` for `monetary`, `maxLength` for `text` and `long-text`, and
|
|
28
|
+
* `placeholder` for the inputs.
|
|
29
29
|
*/
|
|
30
30
|
export type CustomFieldSettings = {
|
|
31
31
|
options?: CustomFieldOption[]
|
|
@@ -47,3 +47,12 @@ expectType<Promise<DashboardPeriodItem[] | DashboardGrouped<DashboardPeriodItem>
|
|
|
47
47
|
expectError(dashboard.getByPeriod({ grouping: 'quarterly' }))
|
|
48
48
|
expectError(dashboard.getByTopic({ withTotals: true }))
|
|
49
49
|
expectError(dashboard.getByService({ withTotals: true }))
|
|
50
|
+
|
|
51
|
+
// ── one connection, tag and subject (not a list) ────────────────────
|
|
52
|
+
|
|
53
|
+
expectType<Promise<DashboardPeriodItem[]>>(
|
|
54
|
+
dashboard.getByPeriod({ serviceId: 's-1', tagId: 't-1', ticketTopicId: 'tt-1' }),
|
|
55
|
+
)
|
|
56
|
+
expectError(dashboard.getByPeriod({ serviceId: ['s-1', 's-2'] }))
|
|
57
|
+
expectError(dashboard.getByPeriod({ tagId: ['t-1'] }))
|
|
58
|
+
expectError(dashboard.getByPeriod({ ticketTopicId: ['tt-1'] }))
|
|
@@ -12,9 +12,9 @@ import type {
|
|
|
12
12
|
} from './types'
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Service statistics ("Estatísticas de atendimento").
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* Service statistics ("Estatísticas de atendimento"). Every route takes the same
|
|
16
|
+
* {@link DashboardQuery} filters; the grouped routes answer one item per day, user, department,
|
|
17
|
+
* topic or connection.
|
|
18
18
|
*/
|
|
19
19
|
export class DashboardApi extends BaseApi {
|
|
20
20
|
public readonly basePath = '/dashboard'
|
|
@@ -14,7 +14,11 @@ export type DashboardQuery = {
|
|
|
14
14
|
startPeriod?: string
|
|
15
15
|
/** ISO date-time. Default: the end of the `startPeriod` day (or of today). */
|
|
16
16
|
endPeriod?: string
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Which ticket date the period filters: opening (`openDate`, the default) or closing. Sent
|
|
19
|
+
* without it, together with `status: 'all'`, the period is not applied. `getByPeriod` needs it:
|
|
20
|
+
* always send it there (the `openDate` default does not apply to that route).
|
|
21
|
+
*/
|
|
18
22
|
periodType?: 'openDate' | 'closeDate'
|
|
19
23
|
/** Ticket status (`closed`, not `close`). */
|
|
20
24
|
status?: 'all' | 'open' | 'closed'
|
|
@@ -39,9 +43,12 @@ export type DashboardQuery = {
|
|
|
39
43
|
*/
|
|
40
44
|
userParticipation?: 'last' | 'middle'
|
|
41
45
|
userStatus?: 'active' | 'archived' | 'all'
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
/** One connection id (unlike `departmentId` and `userId`, not a list). */
|
|
47
|
+
serviceId?: string
|
|
48
|
+
/** One tag id (not a list). */
|
|
49
|
+
tagId?: string
|
|
50
|
+
/** One ticket subject id (not a list). */
|
|
51
|
+
ticketTopicId?: string
|
|
45
52
|
/**
|
|
46
53
|
* Granularity of the `getByPeriod` items (the other routes ignore it). Default: `daily`. See
|
|
47
54
|
* {@link DashboardGrouping} for the `name` of the items.
|
|
@@ -21,11 +21,11 @@ export class DepartmentsApi extends ArchivableCrudApi<
|
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Archives (`archive: true`) or restores (`archive: false`) a department through the route used
|
|
24
|
-
* by the UI
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* connections, marks its schedules as done and unlinks its users and quick replies. Resolves
|
|
28
|
-
* stored department (not transformed); an unknown id answers 500.
|
|
24
|
+
* by the UI: archiving refuses (403 `Cannot archive department.`) a department in use, or when it
|
|
25
|
+
* is the only active department of the account (the `extra` of the error is an
|
|
26
|
+
* `ArchiveDepartmentErrorExtra`). Archiving also clears it as the default department of contacts
|
|
27
|
+
* and connections, marks its schedules as done and unlinks its users and quick replies. Resolves
|
|
28
|
+
* the stored department (not transformed); an unknown id answers 500.
|
|
29
29
|
* @permissions departments.view OR departments.archive
|
|
30
30
|
*/
|
|
31
31
|
archiveWithValidation(
|
|
@@ -32,3 +32,16 @@ export type ArchiveDepartmentPayload = {
|
|
|
32
32
|
/** `true` archives, `false` restores. */
|
|
33
33
|
archive: boolean
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
/** The `extra` of the 403 `Cannot archive department.` error of `archiveWithValidation`. */
|
|
37
|
+
export type ArchiveDepartmentErrorExtra = {
|
|
38
|
+
reasons: (
|
|
39
|
+
| 'ONLY_ONE'
|
|
40
|
+
| 'USED_BOT'
|
|
41
|
+
| 'DEFAULT_DEPARTMENT'
|
|
42
|
+
| 'VISIBILITY_SETTINGS'
|
|
43
|
+
| 'OPEN_TICKETS'
|
|
44
|
+
)[]
|
|
45
|
+
/** Only with open tickets. */
|
|
46
|
+
openTicketsCount?: number
|
|
47
|
+
}
|
|
@@ -34,10 +34,9 @@ export class DistributionApi extends BaseCrudApi<
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Updates a distribution.
|
|
38
|
-
* the
|
|
39
|
-
*
|
|
40
|
-
* answers 500.
|
|
37
|
+
* Updates a distribution. It replaces the links: omitting `roles` or `departments` clears them.
|
|
38
|
+
* Resolves the stored distribution (with `deletedAt`, without the links) or, when `departments`
|
|
39
|
+
* is sent, the updated departments. An unknown id answers 500.
|
|
41
40
|
* @permissions distribution.view OR distribution.update
|
|
42
41
|
*/
|
|
43
42
|
override updateById(
|
|
@@ -43,4 +43,25 @@ describe('KanbanCardsApi', () => {
|
|
|
43
43
|
await expect(api.reorder('kc1', {})).rejects.toThrow('Invalid reorder operation.')
|
|
44
44
|
})
|
|
45
45
|
})
|
|
46
|
+
|
|
47
|
+
describe('getById / create / updateById', () => {
|
|
48
|
+
it('keep the generic routes of /kanban-cards', async () => {
|
|
49
|
+
vi.mocked(client.get).mockResolvedValue({ id: 'kc1' })
|
|
50
|
+
vi.mocked(client.post).mockResolvedValue({ id: 'kc1' })
|
|
51
|
+
vi.mocked(client.put).mockResolvedValue({ id: 'kc1' })
|
|
52
|
+
await api.getById('kc1', { attributes: ['id'] }, headers)
|
|
53
|
+
await api.create({ columnId: 'col1', ticketId: 't1' }, headers)
|
|
54
|
+
await api.updateById('kc1', { columnId: 'col2' }, headers)
|
|
55
|
+
expect(client.get).toHaveBeenCalledWith(
|
|
56
|
+
`/kanban-cards/kc1?query=${encodeURIComponent(JSON.stringify({ attributes: ['id'] }))}`,
|
|
57
|
+
headers,
|
|
58
|
+
)
|
|
59
|
+
expect(client.post).toHaveBeenCalledWith(
|
|
60
|
+
'/kanban-cards',
|
|
61
|
+
{ columnId: 'col1', ticketId: 't1' },
|
|
62
|
+
headers,
|
|
63
|
+
)
|
|
64
|
+
expect(client.put).toHaveBeenCalledWith('/kanban-cards/kc1', { columnId: 'col2' }, headers)
|
|
65
|
+
})
|
|
66
|
+
})
|
|
46
67
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ApiClient } from '../../core/ApiClient'
|
|
2
|
-
import type { ListQuery } from '../../core/types'
|
|
2
|
+
import type { GetByIdQuery, ListQuery } from '../../core/types'
|
|
3
3
|
import { BaseCrudApi } from '../../core/BaseCrudApi'
|
|
4
4
|
import type {
|
|
5
5
|
KanbanCard,
|
|
@@ -8,6 +8,13 @@ import type {
|
|
|
8
8
|
UpdateKanbanCardPayload,
|
|
9
9
|
} from './types'
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Cards of the kanban boards: one per ticket in each board. The reads need `kanban.boards.view`
|
|
13
|
+
* and the writes `kanban.cards.move`. `getMany` takes the column in `where.columnId`. The errors of
|
|
14
|
+
* the writes (unknown column or ticket, ticket of a department not linked to the board, a second
|
|
15
|
+
* card of the ticket in the board, an update by a user outside the department of the ticket)
|
|
16
|
+
* answer 500.
|
|
17
|
+
*/
|
|
11
18
|
export class KanbanCardsApi extends BaseCrudApi<
|
|
12
19
|
KanbanCard,
|
|
13
20
|
CreateKanbanCardPayload,
|
|
@@ -19,6 +26,45 @@ export class KanbanCardsApi extends BaseCrudApi<
|
|
|
19
26
|
super(client, '/kanban-cards')
|
|
20
27
|
}
|
|
21
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Returns a card by ID. An unknown id answers 404 `Kanban card not found.`.
|
|
31
|
+
* @permissions kanban.boards.view
|
|
32
|
+
*/
|
|
33
|
+
override getById(
|
|
34
|
+
id: string,
|
|
35
|
+
query?: GetByIdQuery<KanbanCard>,
|
|
36
|
+
headers?: Record<string, string>,
|
|
37
|
+
): Promise<KanbanCard> {
|
|
38
|
+
return super.getById(id, query, headers)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Creates the card of a ticket in a column. The ticket must be of a department linked to the
|
|
43
|
+
* board and have no card in it yet.
|
|
44
|
+
* @permissions kanban.cards.move
|
|
45
|
+
*/
|
|
46
|
+
override create(
|
|
47
|
+
body: CreateKanbanCardPayload,
|
|
48
|
+
headers?: Record<string, string>,
|
|
49
|
+
): Promise<KanbanCard> {
|
|
50
|
+
return super.create(body, headers)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Updates a card. To move it, use {@link reorder}: `updateById` does not recalculate the
|
|
55
|
+
* `position` and does not close or reopen the ticket. The user must belong to the
|
|
56
|
+
* department of the card's ticket (of the new `ticketId` when sent), or have
|
|
57
|
+
* `tickets.transfer.all`, or be admin; otherwise 500.
|
|
58
|
+
* @permissions kanban.cards.move
|
|
59
|
+
*/
|
|
60
|
+
override updateById(
|
|
61
|
+
id: string,
|
|
62
|
+
body: UpdateKanbanCardPayload,
|
|
63
|
+
headers?: Record<string, string>,
|
|
64
|
+
): Promise<KanbanCard> {
|
|
65
|
+
return super.updateById(id, body, headers)
|
|
66
|
+
}
|
|
67
|
+
|
|
22
68
|
/**
|
|
23
69
|
* Deletes a card. Resolves the text `'OK'`.
|
|
24
70
|
* @permissions kanban.cards.move
|
|
@@ -27,7 +27,7 @@ export type CreateKanbanCardPayload = {
|
|
|
27
27
|
export type UpdateKanbanCardPayload = {
|
|
28
28
|
columnId?: string
|
|
29
29
|
position?: string
|
|
30
|
-
/**
|
|
30
|
+
/** Moves the card to another ticket (see `KanbanCardsApi.updateById` for who can update it). */
|
|
31
31
|
ticketId?: string
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -43,4 +43,30 @@ describe('KanbanColumnsApi', () => {
|
|
|
43
43
|
await expect(api.reorder('col1', {})).rejects.toThrow('Invalid reorder operation.')
|
|
44
44
|
})
|
|
45
45
|
})
|
|
46
|
+
|
|
47
|
+
describe('deleteById', () => {
|
|
48
|
+
it('calls client.delete with /kanban-columns/:id and resolves the deleted column', async () => {
|
|
49
|
+
vi.mocked(client.delete).mockResolvedValue({ id: 'col1' })
|
|
50
|
+
expect(await api.deleteById('col1', headers)).toEqual({ id: 'col1' })
|
|
51
|
+
expect(client.delete).toHaveBeenCalledWith('/kanban-columns/col1', headers)
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
describe('deleteMovingCards', () => {
|
|
56
|
+
it('sends DELETE /kanban-columns/:id with the destination column in the body', async () => {
|
|
57
|
+
vi.mocked(client.request).mockResolvedValue({ id: 'col1' })
|
|
58
|
+
const body = { cardsDestinationColumnId: 'col2' }
|
|
59
|
+
expect(await api.deleteMovingCards('col1', body, headers)).toEqual({ id: 'col1' })
|
|
60
|
+
expect(client.request).toHaveBeenCalledWith('DELETE', '/kanban-columns/col1', body, headers)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('propagates errors', async () => {
|
|
64
|
+
vi.mocked(client.request).mockRejectedValue(
|
|
65
|
+
new Error('Initial and final columns cannot be deleted.'),
|
|
66
|
+
)
|
|
67
|
+
await expect(
|
|
68
|
+
api.deleteMovingCards('col1', { cardsDestinationColumnId: 'col2' }),
|
|
69
|
+
).rejects.toThrow('Initial and final columns cannot be deleted.')
|
|
70
|
+
})
|
|
71
|
+
})
|
|
46
72
|
})
|