boondmanager-mcp-server 2.15.2 → 2.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/LICENSE +1 -1
- package/NOTICE +16 -2
- package/README.md +60 -15
- package/dist/config/access-policy.d.ts.map +1 -1
- package/dist/config/access-policy.js +6 -18
- package/dist/config/access-policy.js.map +1 -1
- package/dist/config/dictionary-overrides.d.ts.map +1 -1
- package/dist/config/dictionary-overrides.js +2 -12
- package/dist/config/dictionary-overrides.js.map +1 -1
- package/dist/config/env.d.ts +63 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +116 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/profiles.d.ts +22 -8
- package/dist/config/profiles.d.ts.map +1 -1
- package/dist/config/profiles.js +48 -4
- package/dist/config/profiles.js.map +1 -1
- package/dist/constants.d.ts +13 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +25 -1
- package/dist/constants.js.map +1 -1
- package/dist/icons.d.ts.map +1 -1
- package/dist/icons.js +6 -1
- package/dist/icons.js.map +1 -1
- package/dist/index.js +33 -15
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.d.ts.map +1 -1
- package/dist/instructions.js +6 -6
- package/dist/instructions.js.map +1 -1
- package/dist/prompts/index.d.ts +19 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +495 -25
- package/dist/prompts/index.js.map +1 -1
- package/dist/prompts/periods.d.ts +45 -0
- package/dist/prompts/periods.d.ts.map +1 -0
- package/dist/prompts/periods.js +154 -0
- package/dist/prompts/periods.js.map +1 -0
- package/dist/resources/index.d.ts +14 -0
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +285 -0
- package/dist/resources/index.js.map +1 -1
- package/dist/resources/templates.d.ts +1 -1
- package/dist/resources/templates.d.ts.map +1 -1
- package/dist/resources/templates.js +2 -0
- package/dist/resources/templates.js.map +1 -1
- package/dist/schema-dialect.js.map +1 -1
- package/dist/schemas/filter-aliases.d.ts +1 -1
- package/dist/schemas/filter-aliases.d.ts.map +1 -1
- package/dist/schemas/filter-aliases.js +101 -2
- package/dist/schemas/filter-aliases.js.map +1 -1
- package/dist/schemas/index.d.ts +987 -161
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +853 -323
- package/dist/schemas/index.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -3
- package/dist/server.js.map +1 -1
- package/dist/services/boond-client.d.ts +29 -213
- package/dist/services/boond-client.d.ts.map +1 -1
- package/dist/services/boond-client.js +29 -1168
- package/dist/services/boond-client.js.map +1 -1
- package/dist/services/dictionary.d.ts +27 -3
- package/dist/services/dictionary.d.ts.map +1 -1
- package/dist/services/dictionary.js +60 -23
- package/dist/services/dictionary.js.map +1 -1
- package/dist/services/document-text.d.ts +32 -0
- package/dist/services/document-text.d.ts.map +1 -0
- package/dist/services/document-text.js +120 -0
- package/dist/services/document-text.js.map +1 -0
- package/dist/services/format/detail.d.ts +16 -0
- package/dist/services/format/detail.d.ts.map +1 -0
- package/dist/services/format/detail.js +36 -0
- package/dist/services/format/detail.js.map +1 -0
- package/dist/services/format/html.d.ts +19 -0
- package/dist/services/format/html.d.ts.map +1 -0
- package/dist/services/format/html.js +87 -0
- package/dist/services/format/html.js.map +1 -0
- package/dist/services/format/list.d.ts +3 -0
- package/dist/services/format/list.d.ts.map +1 -0
- package/dist/services/format/list.js +44 -0
- package/dist/services/format/list.js.map +1 -0
- package/dist/services/format/summary.d.ts +16 -0
- package/dist/services/format/summary.d.ts.map +1 -0
- package/dist/services/format/summary.js +172 -0
- package/dist/services/format/summary.js.map +1 -0
- package/dist/services/format/tab.d.ts +9 -0
- package/dist/services/format/tab.d.ts.map +1 -0
- package/dist/services/format/tab.js +32 -0
- package/dist/services/format/tab.js.map +1 -0
- package/dist/services/http/auth.d.ts +44 -0
- package/dist/services/http/auth.d.ts.map +1 -0
- package/dist/services/http/auth.js +146 -0
- package/dist/services/http/auth.js.map +1 -0
- package/dist/services/http/download.d.ts +60 -0
- package/dist/services/http/download.d.ts.map +1 -0
- package/dist/services/http/download.js +160 -0
- package/dist/services/http/download.js.map +1 -0
- package/dist/services/http/errors.d.ts +45 -0
- package/dist/services/http/errors.d.ts.map +1 -0
- package/dist/services/http/errors.js +188 -0
- package/dist/services/http/errors.js.map +1 -0
- package/dist/services/http/rate-limit.d.ts +40 -0
- package/dist/services/http/rate-limit.d.ts.map +1 -0
- package/dist/services/http/rate-limit.js +92 -0
- package/dist/services/http/rate-limit.js.map +1 -0
- package/dist/services/http/retry.d.ts +46 -0
- package/dist/services/http/retry.d.ts.map +1 -0
- package/dist/services/http/retry.js +101 -0
- package/dist/services/http/retry.js.map +1 -0
- package/dist/services/http/transport.d.ts +73 -0
- package/dist/services/http/transport.d.ts.map +1 -0
- package/dist/services/http/transport.js +272 -0
- package/dist/services/http/transport.js.map +1 -0
- package/dist/services/logger.d.ts +53 -2
- package/dist/services/logger.d.ts.map +1 -1
- package/dist/services/logger.js +82 -21
- package/dist/services/logger.js.map +1 -1
- package/dist/services/oauth.d.ts +12 -0
- package/dist/services/oauth.d.ts.map +1 -1
- package/dist/services/oauth.js +21 -8
- package/dist/services/oauth.js.map +1 -1
- package/dist/services/rate-limiter.d.ts +9 -2
- package/dist/services/rate-limiter.d.ts.map +1 -1
- package/dist/services/rate-limiter.js +18 -6
- package/dist/services/rate-limiter.js.map +1 -1
- package/dist/services/request-context.d.ts +47 -0
- package/dist/services/request-context.d.ts.map +1 -0
- package/dist/services/request-context.js +112 -0
- package/dist/services/request-context.js.map +1 -0
- package/dist/services/search.d.ts +26 -0
- package/dist/services/search.d.ts.map +1 -0
- package/dist/services/search.js +98 -0
- package/dist/services/search.js.map +1 -0
- package/dist/services/update-checker.d.ts.map +1 -1
- package/dist/services/update-checker.js +15 -8
- package/dist/services/update-checker.js.map +1 -1
- package/dist/tools/absences.d.ts +9 -0
- package/dist/tools/absences.d.ts.map +1 -1
- package/dist/tools/absences.js +65 -20
- package/dist/tools/absences.js.map +1 -1
- package/dist/tools/actions.d.ts.map +1 -1
- package/dist/tools/actions.js +11 -27
- package/dist/tools/actions.js.map +1 -1
- package/dist/tools/advantages.d.ts +2 -0
- package/dist/tools/advantages.d.ts.map +1 -1
- package/dist/tools/advantages.js +66 -13
- package/dist/tools/advantages.js.map +1 -1
- package/dist/tools/alerts.d.ts +18 -0
- package/dist/tools/alerts.d.ts.map +1 -0
- package/dist/tools/alerts.js +82 -0
- package/dist/tools/alerts.js.map +1 -0
- package/dist/tools/application.d.ts +2 -1
- package/dist/tools/application.d.ts.map +1 -1
- package/dist/tools/application.js +9 -3
- package/dist/tools/application.js.map +1 -1
- package/dist/tools/contacts.d.ts.map +1 -1
- package/dist/tools/contacts.js +3 -7
- package/dist/tools/contacts.js.map +1 -1
- package/dist/tools/contracts.d.ts +22 -0
- package/dist/tools/contracts.d.ts.map +1 -1
- package/dist/tools/contracts.js +185 -52
- package/dist/tools/contracts.js.map +1 -1
- package/dist/tools/crud-factory.d.ts +33 -2
- package/dist/tools/crud-factory.d.ts.map +1 -1
- package/dist/tools/crud-factory.js +42 -15
- package/dist/tools/crud-factory.js.map +1 -1
- package/dist/tools/deliveries.d.ts +3 -0
- package/dist/tools/deliveries.d.ts.map +1 -1
- package/dist/tools/deliveries.js +50 -94
- package/dist/tools/deliveries.js.map +1 -1
- package/dist/tools/description-builders.d.ts +0 -1
- package/dist/tools/description-builders.d.ts.map +1 -1
- package/dist/tools/description-builders.js +46 -3
- package/dist/tools/description-builders.js.map +1 -1
- package/dist/tools/documents.d.ts.map +1 -1
- package/dist/tools/documents.js +73 -21
- package/dist/tools/documents.js.map +1 -1
- package/dist/tools/expenses.d.ts.map +1 -1
- package/dist/tools/expenses.js +2 -11
- package/dist/tools/expenses.js.map +1 -1
- package/dist/tools/find.d.ts +61 -0
- package/dist/tools/find.d.ts.map +1 -0
- package/dist/tools/find.js +221 -0
- package/dist/tools/find.js.map +1 -0
- package/dist/tools/flags.d.ts +5 -0
- package/dist/tools/flags.d.ts.map +1 -1
- package/dist/tools/flags.js +116 -1
- package/dist/tools/flags.js.map +1 -1
- package/dist/tools/forms.d.ts +5 -0
- package/dist/tools/forms.d.ts.map +1 -0
- package/dist/tools/forms.js +64 -0
- package/dist/tools/forms.js.map +1 -0
- package/dist/tools/groupments.d.ts +5 -0
- package/dist/tools/groupments.d.ts.map +1 -0
- package/dist/tools/groupments.js +68 -0
- package/dist/tools/groupments.js.map +1 -0
- package/dist/tools/inactivities.d.ts +5 -0
- package/dist/tools/inactivities.d.ts.map +1 -0
- package/dist/tools/inactivities.js +59 -0
- package/dist/tools/inactivities.js.map +1 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/invoices.d.ts.map +1 -1
- package/dist/tools/invoices.js +27 -2
- package/dist/tools/invoices.js.map +1 -1
- package/dist/tools/linked-entity-filters.d.ts +48 -0
- package/dist/tools/linked-entity-filters.d.ts.map +1 -0
- package/dist/tools/linked-entity-filters.js +64 -0
- package/dist/tools/linked-entity-filters.js.map +1 -0
- package/dist/tools/notifications.d.ts.map +1 -1
- package/dist/tools/notifications.js +0 -5
- package/dist/tools/notifications.js.map +1 -1
- package/dist/tools/orders.d.ts.map +1 -1
- package/dist/tools/orders.js +33 -4
- package/dist/tools/orders.js.map +1 -1
- package/dist/tools/parameter-disclosure.js.map +1 -1
- package/dist/tools/payments.d.ts +3 -0
- package/dist/tools/payments.d.ts.map +1 -1
- package/dist/tools/payments.js +43 -109
- package/dist/tools/payments.js.map +1 -1
- package/dist/tools/positionings.d.ts.map +1 -1
- package/dist/tools/positionings.js +9 -39
- package/dist/tools/positionings.js.map +1 -1
- package/dist/tools/projects.d.ts.map +1 -1
- package/dist/tools/projects.js +5 -12
- package/dist/tools/projects.js.map +1 -1
- package/dist/tools/provider-invoices.d.ts +2 -0
- package/dist/tools/provider-invoices.d.ts.map +1 -1
- package/dist/tools/provider-invoices.js +30 -111
- package/dist/tools/provider-invoices.js.map +1 -1
- package/dist/tools/purchases.d.ts +2 -0
- package/dist/tools/purchases.d.ts.map +1 -1
- package/dist/tools/purchases.js +50 -104
- package/dist/tools/purchases.js.map +1 -1
- package/dist/tools/registration-decorators.d.ts +28 -0
- package/dist/tools/registration-decorators.d.ts.map +1 -1
- package/dist/tools/registration-decorators.js +107 -0
- package/dist/tools/registration-decorators.js.map +1 -1
- package/dist/tools/resources.d.ts.map +1 -1
- package/dist/tools/resources.js +27 -5
- package/dist/tools/resources.js.map +1 -1
- package/dist/tools/rights.d.ts +101 -0
- package/dist/tools/rights.d.ts.map +1 -0
- package/dist/tools/rights.js +75 -0
- package/dist/tools/rights.js.map +1 -0
- package/dist/tools/tab-tools.js +3 -3
- package/dist/tools/tab-tools.js.map +1 -1
- package/dist/tools/timesheets.d.ts +29 -0
- package/dist/tools/timesheets.d.ts.map +1 -1
- package/dist/tools/timesheets.js +196 -126
- package/dist/tools/timesheets.js.map +1 -1
- package/dist/tools/todolists.d.ts +2 -0
- package/dist/tools/todolists.d.ts.map +1 -1
- package/dist/tools/todolists.js +64 -1
- package/dist/tools/todolists.js.map +1 -1
- package/dist/tools/validations.d.ts +9 -0
- package/dist/tools/validations.d.ts.map +1 -1
- package/dist/tools/validations.js +86 -9
- package/dist/tools/validations.js.map +1 -1
- package/dist/tools/workflows.js +1 -1
- package/dist/tools/workflows.js.map +1 -1
- package/dist/transports/http.d.ts +116 -0
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +422 -92
- package/dist/transports/http.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.d.ts.map +1 -1
- package/manifest.json +7 -7
- package/package.json +14 -10
package/dist/schemas/index.js
CHANGED
|
@@ -24,7 +24,7 @@ export const fieldsField = z
|
|
|
24
24
|
// ("Too big: expected number to be <=100") says what was refused but not what
|
|
25
25
|
// to do instead, and a model that hit the page ceiling should refine its
|
|
26
26
|
// filters rather than retry one page lower.
|
|
27
|
-
const pageField = z
|
|
27
|
+
export const pageField = z
|
|
28
28
|
.number()
|
|
29
29
|
.int()
|
|
30
30
|
.min(1)
|
|
@@ -33,15 +33,27 @@ const pageField = z
|
|
|
33
33
|
})
|
|
34
34
|
.default(1)
|
|
35
35
|
.describe(`Numéro de page (défaut: 1, max: ${MAX_SEARCH_PAGE})`);
|
|
36
|
-
const pageSizeField = z
|
|
36
|
+
export const pageSizeField = z
|
|
37
37
|
.number()
|
|
38
38
|
.int()
|
|
39
39
|
.min(1)
|
|
40
40
|
.max(MAX_PAGE_SIZE, { error: `pageSize > ${MAX_PAGE_SIZE} refusé : maximum ${MAX_PAGE_SIZE} résultats par page.` })
|
|
41
41
|
.default(DEFAULT_PAGE_SIZE)
|
|
42
42
|
.describe(`Nombre de résultats par page (max: ${MAX_PAGE_SIZE}, défaut: ${DEFAULT_PAGE_SIZE})`);
|
|
43
|
-
const sortField = z.string().optional().describe("Champ de tri (ex: lastName, firstName, updateDate)");
|
|
44
|
-
const orderField = z.enum(["asc", "desc"]).optional().describe("Ordre de tri (asc/desc)");
|
|
43
|
+
export const sortField = z.string().optional().describe("Champ de tri (ex: lastName, firstName, updateDate)");
|
|
44
|
+
export const orderField = z.enum(["asc", "desc"]).optional().describe("Ordre de tri (asc/desc)");
|
|
45
|
+
/** `page` / `pageSize` / `fields` — every paginated search. */
|
|
46
|
+
export const paginationShape = {
|
|
47
|
+
page: pageField,
|
|
48
|
+
pageSize: pageSizeField,
|
|
49
|
+
fields: fieldsField,
|
|
50
|
+
};
|
|
51
|
+
/** `sort` / `order` + pagination — the six entity searches that accept sorting. */
|
|
52
|
+
export const sortedPaginationShape = {
|
|
53
|
+
sort: sortField,
|
|
54
|
+
order: orderField,
|
|
55
|
+
...paginationShape,
|
|
56
|
+
};
|
|
45
57
|
// Integer-id filters take ids, and a model that passes labels ("actif",
|
|
46
58
|
// "Acme") gets an invalid_type issue. Point it at the resolution path in the
|
|
47
59
|
// message itself rather than making it re-read the field description — but at
|
|
@@ -61,9 +73,7 @@ const strArray = (doc) => z.array(z.string()).optional().describe(doc);
|
|
|
61
73
|
export const SearchSchema = z
|
|
62
74
|
.object({
|
|
63
75
|
keywords: z.string().optional().describe("Mots-clés de recherche (nom, email, compétences...)"),
|
|
64
|
-
|
|
65
|
-
pageSize: pageSizeField,
|
|
66
|
-
fields: fieldsField,
|
|
76
|
+
...paginationShape,
|
|
67
77
|
})
|
|
68
78
|
.strict();
|
|
69
79
|
// Shared `tools` (technologies/skills) filter. Centralised so every entity
|
|
@@ -106,6 +116,90 @@ const endDateField = z
|
|
|
106
116
|
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
107
117
|
.optional()
|
|
108
118
|
.describe("Date de fin (YYYY-MM-DD), à utiliser avec `period`.");
|
|
119
|
+
// ---- Shared filters of the finance / activity searches (issue #248) ----
|
|
120
|
+
// `/invoices`, `/orders`, `/actions`, `/times-reports`, `/absences-reports`,
|
|
121
|
+
// `/deliveries-groupments` and `/payments` all declare the RAML trait
|
|
122
|
+
// `searchable`, so they take the six `perimeter*` filters — verified live on
|
|
123
|
+
// 2026-09-26 (`perimeterDynamic=data` reduced every one of them). The
|
|
124
|
+
// vocabulary below is per endpoint and was read from each `search.raml`.
|
|
125
|
+
/** `periodDynamic` — the relative windows the RAML lists on every dated search (no `startDate` / `endDate` needed). */
|
|
126
|
+
const periodDynamicField = z
|
|
127
|
+
.enum([
|
|
128
|
+
"today",
|
|
129
|
+
"yesterday",
|
|
130
|
+
"tomorrow",
|
|
131
|
+
"thisWeek",
|
|
132
|
+
"lastWeek",
|
|
133
|
+
"nextWeek",
|
|
134
|
+
"thisMonth",
|
|
135
|
+
"lastMonth",
|
|
136
|
+
"nextMonth",
|
|
137
|
+
"thisTrimester",
|
|
138
|
+
"lastTrimester",
|
|
139
|
+
"nextTrimester",
|
|
140
|
+
"thisSemester",
|
|
141
|
+
"lastSemester",
|
|
142
|
+
"nextSemester",
|
|
143
|
+
"thisYear",
|
|
144
|
+
"lastYear",
|
|
145
|
+
"nextYear",
|
|
146
|
+
"thisFiscalYear",
|
|
147
|
+
"lastFiscalYear",
|
|
148
|
+
"nextFiscalYear",
|
|
149
|
+
"untilToday",
|
|
150
|
+
])
|
|
151
|
+
.optional()
|
|
152
|
+
.describe("Fenêtre relative appliquée à `period` (à la place de `startDate` / `endDate`) : today, thisWeek, thisMonth, lastMonth, thisYear, untilToday…");
|
|
153
|
+
const flagsField = entityIdArray("IDs de drapeaux (flags) — `boond_flags_search`.");
|
|
154
|
+
/** The validation workflow of a CRA / absence report is a string state, not a dictionary id (#250). */
|
|
155
|
+
const validationStatesField = z
|
|
156
|
+
.array(z.enum(["waitingForValidation", "validated", "rejected"]))
|
|
157
|
+
.optional()
|
|
158
|
+
.describe("États du workflow de validation : waitingForValidation (à valider), validated, rejected.");
|
|
159
|
+
const resourceTypesField = intArray("IDs de types de ressource — `boond://dictionary/typeOf/resources`.");
|
|
160
|
+
const paymentMethodsField = intArray("IDs de modes de paiement — `boond://dictionary/paymentMethods`.");
|
|
161
|
+
const projectTypesFilterField = intArray("IDs de types de projet — `boond://dictionary/typeOf/projects`.");
|
|
162
|
+
const companiesFilterField = entityIdArray("IDs de sociétés (filtre API natif, équivalent de `companyId` pour plusieurs sociétés).");
|
|
163
|
+
// ---- Shared shapes (issue #240) ----
|
|
164
|
+
// Composed by spread into the entity search schemas so a change to one field
|
|
165
|
+
// (a `.describe()`, the page-ceiling message) propagates everywhere. Before,
|
|
166
|
+
// the six perimeter fields were copied six times, `shields` five times and the
|
|
167
|
+
// `page`/`pageSize` pair ~16 times — ten of those copies had already lost the
|
|
168
|
+
// `MAX_SEARCH_PAGE` explanation `pageField` carries.
|
|
169
|
+
/** The six RAML-trait `searchable` perimeter filters, in API order. */
|
|
170
|
+
export const perimeterShape = {
|
|
171
|
+
perimeterManagers: perimeterManagersField,
|
|
172
|
+
perimeterAgencies: perimeterAgenciesField,
|
|
173
|
+
perimeterPoles: perimeterPolesField,
|
|
174
|
+
perimeterBusinessUnits: perimeterBusinessUnitsField,
|
|
175
|
+
perimeterDynamic: perimeterDynamicField,
|
|
176
|
+
narrowPerimeter: narrowPerimeterField,
|
|
177
|
+
};
|
|
178
|
+
/** Completeness level of the conditional fields (RAML trait `shields`). */
|
|
179
|
+
export const shieldsField = z
|
|
180
|
+
.array(z.enum(["uncomplete", "minimum", "complete"]))
|
|
181
|
+
.optional()
|
|
182
|
+
.describe("Niveau de complétude des champs conditionnels.");
|
|
183
|
+
/** `keywordsType` values shared by the two people endpoints (resources, candidates). */
|
|
184
|
+
export const peopleKeywordsTypeEnum = z.enum([
|
|
185
|
+
"resumeTd",
|
|
186
|
+
"lastName",
|
|
187
|
+
"firstName",
|
|
188
|
+
"fullName",
|
|
189
|
+
"strictFullName",
|
|
190
|
+
"emails",
|
|
191
|
+
"title",
|
|
192
|
+
"titleSkills",
|
|
193
|
+
"phones",
|
|
194
|
+
"reference",
|
|
195
|
+
"resume",
|
|
196
|
+
"td",
|
|
197
|
+
]);
|
|
198
|
+
/** `perimeterManagersType` — candidates and opportunities only. */
|
|
199
|
+
const perimeterManagersTypeField = z
|
|
200
|
+
.enum(["main", "hr"])
|
|
201
|
+
.optional()
|
|
202
|
+
.describe("Type de responsable visé par `perimeterManagers`: 'main' (Main Manager) ou 'hr' (HR Manager).");
|
|
109
203
|
// ---- Resource search schema (collaborateurs internes) ----
|
|
110
204
|
// Source: https://doc.boondmanager.com/api-externe/raml-build/resources/resources/search.raml
|
|
111
205
|
export const ResourceSearchSchema = z
|
|
@@ -115,30 +209,11 @@ export const ResourceSearchSchema = z
|
|
|
115
209
|
.optional()
|
|
116
210
|
.describe("Mots-clés (par défaut, recherche dans CV + dossier technique). Pour cibler un champ précis, " +
|
|
117
211
|
"fournir aussi `keywordsType` (ex: lastName, firstName, fullName, emails, title, titleSkills, phones, reference)."),
|
|
118
|
-
keywordsType:
|
|
119
|
-
.enum([
|
|
120
|
-
"resumeTd",
|
|
121
|
-
"lastName",
|
|
122
|
-
"firstName",
|
|
123
|
-
"fullName",
|
|
124
|
-
"strictFullName",
|
|
125
|
-
"emails",
|
|
126
|
-
"title",
|
|
127
|
-
"titleSkills",
|
|
128
|
-
"phones",
|
|
129
|
-
"reference",
|
|
130
|
-
"resume",
|
|
131
|
-
"td",
|
|
132
|
-
])
|
|
212
|
+
keywordsType: peopleKeywordsTypeEnum
|
|
133
213
|
.optional()
|
|
134
214
|
.describe("Champ ciblé par `keywords`. Défaut: 'resumeTd' (CV + dossier technique). " +
|
|
135
215
|
"Pour 'fullName' utiliser `keywords = 'NOM#PRENOM'`."),
|
|
136
|
-
|
|
137
|
-
perimeterAgencies: perimeterAgenciesField,
|
|
138
|
-
perimeterPoles: perimeterPolesField,
|
|
139
|
-
perimeterBusinessUnits: perimeterBusinessUnitsField,
|
|
140
|
-
perimeterDynamic: perimeterDynamicField,
|
|
141
|
-
narrowPerimeter: narrowPerimeterField,
|
|
216
|
+
...perimeterShape,
|
|
142
217
|
resourceStates: intArray("IDs d'états de ressource (dictionnaire setting.state.resource via boond_application_dictionary)."),
|
|
143
218
|
excludeResourceStates: intArray("IDs d'états de ressource à EXCLURE."),
|
|
144
219
|
resourceTypes: intArray("IDs de types de ressource (dictionnaire setting.typeOf.resource)."),
|
|
@@ -178,15 +253,8 @@ export const ResourceSearchSchema = z
|
|
|
178
253
|
.optional()
|
|
179
254
|
.describe("Rayon en km pour la recherche géographique (5-200). Requis si `coordinates` ou `location` est fourni."),
|
|
180
255
|
excludeManager: z.boolean().optional().describe("Si true, ne retourne que les ressources sans compte manager."),
|
|
181
|
-
shields:
|
|
182
|
-
|
|
183
|
-
.optional()
|
|
184
|
-
.describe("Niveau de complétude des champs conditionnels."),
|
|
185
|
-
sort: sortField,
|
|
186
|
-
order: orderField,
|
|
187
|
-
page: pageField,
|
|
188
|
-
pageSize: pageSizeField,
|
|
189
|
-
fields: fieldsField,
|
|
256
|
+
shields: shieldsField,
|
|
257
|
+
...sortedPaginationShape,
|
|
190
258
|
})
|
|
191
259
|
.strict();
|
|
192
260
|
// ---- Candidate search schema ----
|
|
@@ -197,33 +265,9 @@ export const CandidateSearchSchema = z
|
|
|
197
265
|
.string()
|
|
198
266
|
.optional()
|
|
199
267
|
.describe("Mots-clés (par défaut, recherche dans CV + dossier technique). Combinable avec `keywordsType`."),
|
|
200
|
-
keywordsType:
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
"lastName",
|
|
204
|
-
"firstName",
|
|
205
|
-
"fullName",
|
|
206
|
-
"strictFullName",
|
|
207
|
-
"emails",
|
|
208
|
-
"title",
|
|
209
|
-
"titleSkills",
|
|
210
|
-
"phones",
|
|
211
|
-
"reference",
|
|
212
|
-
"resume",
|
|
213
|
-
"td",
|
|
214
|
-
])
|
|
215
|
-
.optional()
|
|
216
|
-
.describe("Champ ciblé par `keywords` (défaut: 'resumeTd')."),
|
|
217
|
-
perimeterManagers: perimeterManagersField,
|
|
218
|
-
perimeterAgencies: perimeterAgenciesField,
|
|
219
|
-
perimeterPoles: perimeterPolesField,
|
|
220
|
-
perimeterBusinessUnits: perimeterBusinessUnitsField,
|
|
221
|
-
perimeterDynamic: perimeterDynamicField,
|
|
222
|
-
perimeterManagersType: z
|
|
223
|
-
.enum(["main", "hr"])
|
|
224
|
-
.optional()
|
|
225
|
-
.describe("Type de responsable visé par `perimeterManagers`: 'main' (Main Manager) ou 'hr' (HR Manager)."),
|
|
226
|
-
narrowPerimeter: narrowPerimeterField,
|
|
268
|
+
keywordsType: peopleKeywordsTypeEnum.optional().describe("Champ ciblé par `keywords` (défaut: 'resumeTd')."),
|
|
269
|
+
...perimeterShape,
|
|
270
|
+
perimeterManagersType: perimeterManagersTypeField,
|
|
227
271
|
candidateStates: intArray("IDs d'états de candidat (dictionnaire setting.state.candidate via boond_application_dictionary)."),
|
|
228
272
|
candidateTypes: intArray("IDs de types de candidat (dictionnaire setting.typeOf.resource)."),
|
|
229
273
|
contractTypes: intArray("IDs de types de contrat recherchés (dictionnaire setting.typeOf.contract)."),
|
|
@@ -249,15 +293,8 @@ export const CandidateSearchSchema = z
|
|
|
249
293
|
coordinates: z.string().optional().describe("Coordonnées GPS 'lat,lon'. Requiert `geoDistance`."),
|
|
250
294
|
location: z.string().optional().describe("Adresse texte. Requiert `geoDistance`."),
|
|
251
295
|
geoDistance: z.number().int().min(5).max(200).optional().describe("Rayon km (5-200)."),
|
|
252
|
-
shields:
|
|
253
|
-
|
|
254
|
-
.optional()
|
|
255
|
-
.describe("Niveau de complétude."),
|
|
256
|
-
sort: sortField,
|
|
257
|
-
order: orderField,
|
|
258
|
-
page: pageField,
|
|
259
|
-
pageSize: pageSizeField,
|
|
260
|
-
fields: fieldsField,
|
|
296
|
+
shields: shieldsField,
|
|
297
|
+
...sortedPaginationShape,
|
|
261
298
|
})
|
|
262
299
|
.strict();
|
|
263
300
|
// ---- Contact search schema ----
|
|
@@ -284,12 +321,7 @@ export const ContactSearchSchema = z
|
|
|
284
321
|
.optional()
|
|
285
322
|
.describe("Champ ciblé. Défaut: 'default'. Pour 'fullName' utiliser `keywords = 'NOM#PRENOM'`. " +
|
|
286
323
|
"Pour 'companyFullName' utiliser `keywords = 'CSOCid#NOM#PRENOM'`."),
|
|
287
|
-
|
|
288
|
-
perimeterAgencies: perimeterAgenciesField,
|
|
289
|
-
perimeterPoles: perimeterPolesField,
|
|
290
|
-
perimeterBusinessUnits: perimeterBusinessUnitsField,
|
|
291
|
-
perimeterDynamic: perimeterDynamicField,
|
|
292
|
-
narrowPerimeter: narrowPerimeterField,
|
|
324
|
+
...perimeterShape,
|
|
293
325
|
states: intArray("IDs d'états de contact (dictionnaire setting.state.contact)."),
|
|
294
326
|
companyStates: intArray("IDs d'états des sociétés rattachées (dictionnaire setting.state.company)."),
|
|
295
327
|
typesOf: intArray("IDs de types de contact (dictionnaire setting.typeOf.contact). " +
|
|
@@ -309,15 +341,8 @@ export const ContactSearchSchema = z
|
|
|
309
341
|
endDate: endDateField,
|
|
310
342
|
completeness: strArray("Filtre par complétude des champs au format `fieldId:mode` (fieldId: email/phone/socialNetworks ; " +
|
|
311
343
|
"mode: empty/filled). Logique OU par défaut, '#AND#' en 1er pour ET. Ex: ['email:empty','phone:empty']."),
|
|
312
|
-
shields:
|
|
313
|
-
|
|
314
|
-
.optional()
|
|
315
|
-
.describe("Niveau de complétude."),
|
|
316
|
-
sort: sortField,
|
|
317
|
-
order: orderField,
|
|
318
|
-
page: pageField,
|
|
319
|
-
pageSize: pageSizeField,
|
|
320
|
-
fields: fieldsField,
|
|
344
|
+
shields: shieldsField,
|
|
345
|
+
...sortedPaginationShape,
|
|
321
346
|
})
|
|
322
347
|
.strict();
|
|
323
348
|
// ---- Company search schema ----
|
|
@@ -332,12 +357,7 @@ export const CompanySearchSchema = z
|
|
|
332
357
|
.enum(["default", "name", "phones", "emails", "socialNetworks"])
|
|
333
358
|
.optional()
|
|
334
359
|
.describe("Champ ciblé par `keywords`. Défaut: 'default'."),
|
|
335
|
-
|
|
336
|
-
perimeterAgencies: perimeterAgenciesField,
|
|
337
|
-
perimeterPoles: perimeterPolesField,
|
|
338
|
-
perimeterBusinessUnits: perimeterBusinessUnitsField,
|
|
339
|
-
perimeterDynamic: perimeterDynamicField,
|
|
340
|
-
narrowPerimeter: narrowPerimeterField,
|
|
360
|
+
...perimeterShape,
|
|
341
361
|
states: intArray("IDs d'états de société (dictionnaire setting.state.company)."),
|
|
342
362
|
expertiseAreas: strArray("IDs de domaines d'expertise (dictionnaire setting.expertiseArea)."),
|
|
343
363
|
origins: strArray("IDs d'origines (dictionnaire setting.origin)."),
|
|
@@ -350,15 +370,8 @@ export const CompanySearchSchema = z
|
|
|
350
370
|
"À combiner avec `startDate` + `endDate`."),
|
|
351
371
|
startDate: startDateField,
|
|
352
372
|
endDate: endDateField,
|
|
353
|
-
shields:
|
|
354
|
-
|
|
355
|
-
.optional()
|
|
356
|
-
.describe("Niveau de complétude."),
|
|
357
|
-
sort: sortField,
|
|
358
|
-
order: orderField,
|
|
359
|
-
page: pageField,
|
|
360
|
-
pageSize: pageSizeField,
|
|
361
|
-
fields: fieldsField,
|
|
373
|
+
shields: shieldsField,
|
|
374
|
+
...sortedPaginationShape,
|
|
362
375
|
})
|
|
363
376
|
.strict();
|
|
364
377
|
// ---- Opportunity search schema ----
|
|
@@ -371,16 +384,8 @@ export const OpportunitySearchSchema = z
|
|
|
371
384
|
.describe("Mots-clés. Pour cibler par ID préfixé : 'AOnnn' (opportunité), 'CSOCnnn' (société), " +
|
|
372
385
|
"'CCONnnn' (contact), 'CANDnnn' (candidat), 'COMPnnn' (ressource), 'PRODnnn' (produit). " +
|
|
373
386
|
"Sinon recherche plein texte sur titre/société."),
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
perimeterPoles: perimeterPolesField,
|
|
377
|
-
perimeterBusinessUnits: perimeterBusinessUnitsField,
|
|
378
|
-
perimeterDynamic: perimeterDynamicField,
|
|
379
|
-
perimeterManagersType: z
|
|
380
|
-
.enum(["main", "hr"])
|
|
381
|
-
.optional()
|
|
382
|
-
.describe("Type de responsable visé par `perimeterManagers` (main/hr)."),
|
|
383
|
-
narrowPerimeter: narrowPerimeterField,
|
|
387
|
+
...perimeterShape,
|
|
388
|
+
perimeterManagersType: perimeterManagersTypeField,
|
|
384
389
|
opportunityStates: intArray("IDs d'états d'opportunité (dictionnaire setting.state.opportunity)."),
|
|
385
390
|
opportunityTypes: strArray("IDs de types d'opportunité (dictionnaire setting.typeOf.project)."),
|
|
386
391
|
positioningStates: strArray("IDs d'états de positionnement, ou 'none' pour les opportunités sans positionnement."),
|
|
@@ -399,15 +404,8 @@ export const OpportunitySearchSchema = z
|
|
|
399
404
|
"À combiner avec `startDate` + `endDate`."),
|
|
400
405
|
startDate: startDateField,
|
|
401
406
|
endDate: endDateField,
|
|
402
|
-
shields:
|
|
403
|
-
|
|
404
|
-
.optional()
|
|
405
|
-
.describe("Niveau de complétude."),
|
|
406
|
-
sort: sortField,
|
|
407
|
-
order: orderField,
|
|
408
|
-
page: pageField,
|
|
409
|
-
pageSize: pageSizeField,
|
|
410
|
-
fields: fieldsField,
|
|
407
|
+
shields: shieldsField,
|
|
408
|
+
...sortedPaginationShape,
|
|
411
409
|
})
|
|
412
410
|
.strict();
|
|
413
411
|
// ---- Project search schema ----
|
|
@@ -419,12 +417,7 @@ export const ProjectSearchSchema = z
|
|
|
419
417
|
.optional()
|
|
420
418
|
.describe("Mots-clés. Pour cibler par ID préfixé : 'PRJnnn' (projet), 'CSOCnnn' (société), " +
|
|
421
419
|
"'CCONnnn' (contact), 'AOnnn' (opportunité), 'COMPnnn' (ressource), 'CTRnnn' (contrat)."),
|
|
422
|
-
|
|
423
|
-
perimeterAgencies: perimeterAgenciesField,
|
|
424
|
-
perimeterPoles: perimeterPolesField,
|
|
425
|
-
perimeterBusinessUnits: perimeterBusinessUnitsField,
|
|
426
|
-
perimeterDynamic: perimeterDynamicField,
|
|
427
|
-
narrowPerimeter: narrowPerimeterField,
|
|
420
|
+
...perimeterShape,
|
|
428
421
|
projectStates: intArray("IDs d'états de projet (dictionnaire setting.state.project)."),
|
|
429
422
|
projectTypes: intArray("IDs de types de projet (dictionnaire setting.typeOf.project)."),
|
|
430
423
|
companies: entityIdArray("IDs de sociétés clientes : projets rattachés à ces sociétés."),
|
|
@@ -438,11 +431,7 @@ export const ProjectSearchSchema = z
|
|
|
438
431
|
"'hasAdditionalDataOrPurchase'. À combiner avec `startDate` + `endDate`."),
|
|
439
432
|
startDate: startDateField,
|
|
440
433
|
endDate: endDateField,
|
|
441
|
-
|
|
442
|
-
order: orderField,
|
|
443
|
-
page: pageField,
|
|
444
|
-
pageSize: pageSizeField,
|
|
445
|
-
fields: fieldsField,
|
|
434
|
+
...sortedPaginationShape,
|
|
446
435
|
})
|
|
447
436
|
.strict();
|
|
448
437
|
// BoondManager entity ids are numeric. Constraining the schema to digits
|
|
@@ -470,6 +459,11 @@ export const IdSchema = z
|
|
|
470
459
|
// the id still can't smuggle a path segment, `..`, `?` or `#` into the API
|
|
471
460
|
// path. Letters are allowed in both cases because Boond derives the suffix
|
|
472
461
|
// from camelCase parent types (`administrativeFile`).
|
|
462
|
+
/** `mode` of `boond_documents_get` (issue #263): extracted text by default, the raw bytes on demand. */
|
|
463
|
+
export const DocumentGetModeSchema = z
|
|
464
|
+
.enum(["text", "raw"])
|
|
465
|
+
.default("text")
|
|
466
|
+
.describe("text (défaut) : PDF et DOCX renvoyés en texte extrait côté serveur, images en contenu `image` ; raw : le fichier tel quel en ressource embarquée (base64).");
|
|
473
467
|
export const DocumentIdSchema = z
|
|
474
468
|
.object({
|
|
475
469
|
id: z
|
|
@@ -478,6 +472,7 @@ export const DocumentIdSchema = z
|
|
|
478
472
|
.describe("Identifiant du document, tel qu'exposé par les relations d'entités (ex. 123_resume)"),
|
|
479
473
|
})
|
|
480
474
|
.strict();
|
|
475
|
+
export const DocumentGetSchema = DocumentIdSchema.extend({ mode: DocumentGetModeSchema }).strict();
|
|
481
476
|
// ID + tab param schema
|
|
482
477
|
export const IdTabSchema = z
|
|
483
478
|
.object({
|
|
@@ -520,13 +515,8 @@ export const CandidateCreateSchema = z
|
|
|
520
515
|
.strict();
|
|
521
516
|
export const PositioningUpdateSchema = z
|
|
522
517
|
.object({
|
|
523
|
-
id:
|
|
524
|
-
state:
|
|
525
|
-
.number()
|
|
526
|
-
.int()
|
|
527
|
-
.min(0)
|
|
528
|
-
.optional()
|
|
529
|
-
.describe("\u00c9tat du positionnement : ID num\u00e9rique du dictionnaire setting.state.positioning"),
|
|
518
|
+
id: EntityIdSchema.describe("ID du positionnement \u00e0 modifier"),
|
|
519
|
+
state: stateField("positioning", "État du positionnement : ID numérique de `boond://dictionary/states/positionings`"),
|
|
530
520
|
stateReasonTypeOf: z
|
|
531
521
|
.number()
|
|
532
522
|
.int()
|
|
@@ -540,7 +530,7 @@ export const PositioningUpdateSchema = z
|
|
|
540
530
|
.strict();
|
|
541
531
|
export const CandidateUpdateSchema = z
|
|
542
532
|
.object({
|
|
543
|
-
id:
|
|
533
|
+
id: EntityIdSchema.describe("ID du candidat à modifier"),
|
|
544
534
|
firstName: z.string().optional().describe("Prénom"),
|
|
545
535
|
lastName: z.string().optional().describe("Nom"),
|
|
546
536
|
email1: z.string().email().optional().describe("Email principal"),
|
|
@@ -569,7 +559,7 @@ export const ResourceCreateSchema = z
|
|
|
569
559
|
.strict();
|
|
570
560
|
export const ResourceUpdateSchema = z
|
|
571
561
|
.object({
|
|
572
|
-
id:
|
|
562
|
+
id: EntityIdSchema.describe("ID de la ressource à modifier"),
|
|
573
563
|
firstName: z.string().optional().describe("Prénom"),
|
|
574
564
|
lastName: z.string().optional().describe("Nom"),
|
|
575
565
|
email1: z.string().email().optional().describe("Email principal"),
|
|
@@ -600,7 +590,7 @@ const technicalDataLanguageItemSchema = z
|
|
|
600
590
|
.strict();
|
|
601
591
|
export const ResourceTechnicalDataUpdateSchema = z
|
|
602
592
|
.object({
|
|
603
|
-
id:
|
|
593
|
+
id: EntityIdSchema.describe("ID de la ressource dont le dossier technique est mis à jour."),
|
|
604
594
|
mode: z
|
|
605
595
|
.enum(["merge", "replace"])
|
|
606
596
|
.default("merge")
|
|
@@ -646,7 +636,7 @@ const referenceYear = z.coerce
|
|
|
646
636
|
.describe("Année (ex: 2024). Accepte int ou string '2024'.");
|
|
647
637
|
export const ReferenceCreateSchema = z
|
|
648
638
|
.object({
|
|
649
|
-
resourceId:
|
|
639
|
+
resourceId: EntityIdSchema.describe("ID de la ressource à laquelle rattacher la référence."),
|
|
650
640
|
title: z.string().min(1).describe("Intitulé du poste."),
|
|
651
641
|
company: z.string().min(1).describe("Société / employeur."),
|
|
652
642
|
description: z
|
|
@@ -663,11 +653,8 @@ export const ReferenceCreateSchema = z
|
|
|
663
653
|
.strict();
|
|
664
654
|
export const ReferenceUpdateSchema = z
|
|
665
655
|
.object({
|
|
666
|
-
resourceId:
|
|
667
|
-
|
|
668
|
-
.min(1)
|
|
669
|
-
.describe("ID de la ressource portant la référence (les references sont embarquées dans le DT)."),
|
|
670
|
-
referenceId: z.string().min(1).describe("ID de la référence à modifier."),
|
|
656
|
+
resourceId: EntityIdSchema.describe("ID de la ressource portant la référence (les references sont embarquées dans le DT)."),
|
|
657
|
+
referenceId: EntityIdSchema.describe("ID de la référence à modifier."),
|
|
671
658
|
title: z.string().optional().describe("Intitulé du poste."),
|
|
672
659
|
company: z.string().optional().describe("Société / employeur."),
|
|
673
660
|
description: z.string().optional().describe("Description / missions / réalisations."),
|
|
@@ -681,11 +668,8 @@ export const ReferenceUpdateSchema = z
|
|
|
681
668
|
.strict();
|
|
682
669
|
export const ReferenceIdSchema = z
|
|
683
670
|
.object({
|
|
684
|
-
resourceId:
|
|
685
|
-
|
|
686
|
-
.min(1)
|
|
687
|
-
.describe("ID de la ressource portant la référence (les references sont embarquées dans le DT)."),
|
|
688
|
-
referenceId: z.string().min(1).describe("ID de la référence à supprimer."),
|
|
671
|
+
resourceId: EntityIdSchema.describe("ID de la ressource portant la référence (les references sont embarquées dans le DT)."),
|
|
672
|
+
referenceId: EntityIdSchema.describe("ID de la référence à supprimer."),
|
|
689
673
|
})
|
|
690
674
|
.strict();
|
|
691
675
|
// ---- Contact schemas ----
|
|
@@ -698,13 +682,13 @@ export const ContactCreateSchema = z
|
|
|
698
682
|
city: z.string().optional().describe("Ville"),
|
|
699
683
|
country: z.string().optional().describe("Pays"),
|
|
700
684
|
title: z.string().optional().describe("Titre / fonction"),
|
|
701
|
-
companyId:
|
|
685
|
+
companyId: EntityIdSchema.optional().describe("ID de la société associée"),
|
|
702
686
|
note: z.string().optional().describe("Notes"),
|
|
703
687
|
})
|
|
704
688
|
.strict();
|
|
705
689
|
export const ContactUpdateSchema = z
|
|
706
690
|
.object({
|
|
707
|
-
id:
|
|
691
|
+
id: EntityIdSchema.describe("ID du contact à modifier"),
|
|
708
692
|
firstName: z.string().optional().describe("Prénom"),
|
|
709
693
|
lastName: z.string().optional().describe("Nom"),
|
|
710
694
|
email1: z.string().email().optional().describe("Email"),
|
|
@@ -730,7 +714,7 @@ export const CompanyCreateSchema = z
|
|
|
730
714
|
.strict();
|
|
731
715
|
export const CompanyUpdateSchema = z
|
|
732
716
|
.object({
|
|
733
|
-
id:
|
|
717
|
+
id: EntityIdSchema.describe("ID de la société à modifier"),
|
|
734
718
|
name: z.string().optional().describe("Nom"),
|
|
735
719
|
email1: z.string().email().optional().describe("Email"),
|
|
736
720
|
phone1: z.string().optional().describe("Téléphone"),
|
|
@@ -759,8 +743,8 @@ const opportunityWritableShape = {
|
|
|
759
743
|
.min(1)
|
|
760
744
|
.optional()
|
|
761
745
|
.describe("Type d'opportunité : ID numérique du dictionnaire setting.typeOf.project (ex: 1, 3), via boond_application_dictionary"),
|
|
762
|
-
companyId:
|
|
763
|
-
contactId:
|
|
746
|
+
companyId: EntityIdSchema.optional().describe("ID de la société cliente (relation company)"),
|
|
747
|
+
contactId: EntityIdSchema.optional().describe("ID du contact associé (relation contact)"),
|
|
764
748
|
state: stateField("opportunity", "État de l'opportunité"),
|
|
765
749
|
startDate: z.string().optional().describe("Date de début prévue (YYYY-MM-DD ou 'immediate')"),
|
|
766
750
|
endDate: z.string().optional().describe("Date de fin prévue (YYYY-MM-DD)"),
|
|
@@ -779,13 +763,10 @@ const opportunityWritableShape = {
|
|
|
779
763
|
.optional()
|
|
780
764
|
.describe("Domaine d'expertise : ID du dictionnaire setting.expertiseArea (via boond_application_dictionary)"),
|
|
781
765
|
turnoverEstimatedExcludingTax: z.coerce.number().optional().describe("Chiffre d'affaires estimé HT (montant)"),
|
|
782
|
-
poleId:
|
|
783
|
-
hrManagerId:
|
|
784
|
-
mainManagerId:
|
|
785
|
-
|
|
786
|
-
.optional()
|
|
787
|
-
.describe("ID de la ressource responsable principal / commercial (relation mainManager)"),
|
|
788
|
-
agencyId: z.string().optional().describe("ID de l'agence (relation agency)"),
|
|
766
|
+
poleId: EntityIdSchema.optional().describe("ID du pôle (relation pole)"),
|
|
767
|
+
hrManagerId: EntityIdSchema.optional().describe("ID de la ressource responsable RH (relation hrManager)"),
|
|
768
|
+
mainManagerId: EntityIdSchema.optional().describe("ID de la ressource responsable principal / commercial (relation mainManager)"),
|
|
769
|
+
agencyId: EntityIdSchema.optional().describe("ID de l'agence (relation agency)"),
|
|
789
770
|
};
|
|
790
771
|
export const OpportunityCreateSchema = z
|
|
791
772
|
.object({
|
|
@@ -795,22 +776,35 @@ export const OpportunityCreateSchema = z
|
|
|
795
776
|
.strict();
|
|
796
777
|
export const OpportunityUpdateSchema = z
|
|
797
778
|
.object({
|
|
798
|
-
id:
|
|
779
|
+
id: EntityIdSchema.describe("ID de l'opportunité à modifier"),
|
|
799
780
|
name: z.string().optional().describe("Nom / titre"),
|
|
800
781
|
...opportunityWritableShape,
|
|
801
782
|
})
|
|
802
783
|
.strict();
|
|
803
784
|
// ---- Action schemas ----
|
|
785
|
+
// Source: resources/actions/search.raml (filters verified live, issue #248).
|
|
804
786
|
export const ActionSearchSchema = z
|
|
805
787
|
.object({
|
|
806
788
|
keywords: z.string().optional().describe("Mots-clés de recherche"),
|
|
807
|
-
candidateId:
|
|
808
|
-
resourceId:
|
|
809
|
-
contactId:
|
|
810
|
-
companyId:
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
789
|
+
candidateId: EntityIdSchema.optional().describe("Filtrer par ID candidat (référence keywords CAND<id>)"),
|
|
790
|
+
resourceId: EntityIdSchema.optional().describe("Filtrer par ID ressource (référence keywords COMP<id>)"),
|
|
791
|
+
contactId: EntityIdSchema.optional().describe("Filtrer par ID contact (référence keywords CCON<id>)"),
|
|
792
|
+
companyId: EntityIdSchema.optional().describe("Filtrer par ID société (référence keywords CSOC<id>)"),
|
|
793
|
+
opportunityId: EntityIdSchema.optional().describe("Filtrer par ID opportunité (référence keywords AO<id>)"),
|
|
794
|
+
projectId: EntityIdSchema.optional().describe("Filtrer par ID projet (référence keywords PRJ<id>)"),
|
|
795
|
+
orderId: EntityIdSchema.optional().describe("Filtrer par ID bon de commande (référence keywords BDC<id>)"),
|
|
796
|
+
invoiceId: EntityIdSchema.optional().describe("Filtrer par ID facture (référence keywords FACT<id>)"),
|
|
797
|
+
actionTypes: intArray("IDs de types d'action — `boond://dictionary/actions/<entité>` (les types sont déclarés par entité de rattachement)."),
|
|
798
|
+
period: z
|
|
799
|
+
.enum(["started", "created", "updated"])
|
|
800
|
+
.optional()
|
|
801
|
+
.describe("Champ de date borné par `startDate` / `endDate` : started (date de l'action), created, updated."),
|
|
802
|
+
periodDynamic: periodDynamicField,
|
|
803
|
+
startDate: startDateField,
|
|
804
|
+
endDate: endDateField,
|
|
805
|
+
flags: flagsField,
|
|
806
|
+
...perimeterShape,
|
|
807
|
+
...sortedPaginationShape,
|
|
814
808
|
})
|
|
815
809
|
.strict();
|
|
816
810
|
// POST /actions requires a polymorphic `dependsOn` relationship (the entity the
|
|
@@ -831,16 +825,13 @@ export const ActionCreateSchema = z
|
|
|
831
825
|
.optional()
|
|
832
826
|
.describe("Date de début au format ISO 8601 avec timezone (ex: 2026-06-05T10:00:00+0200)"),
|
|
833
827
|
endDate: z.string().regex(actionDateTimeRegex).optional().describe("Date de fin (même format que startDate)"),
|
|
834
|
-
candidateId:
|
|
835
|
-
resourceId:
|
|
836
|
-
contactId:
|
|
837
|
-
opportunityId:
|
|
838
|
-
projectId:
|
|
839
|
-
companyId:
|
|
840
|
-
positioningId:
|
|
841
|
-
.string()
|
|
842
|
-
.optional()
|
|
843
|
-
.describe("ID du positionnement à lier à l'action (relation positioning). Requis par l'API pour les types d'action liés aux positionnements (ex. RQ) — sans lui, erreur 422 « 1002 - Wrong or missing attribute (/data/relationships/positioning) »."),
|
|
828
|
+
candidateId: EntityIdSchema.optional().describe("ID du candidat auquel rattacher l'action (dependsOn)"),
|
|
829
|
+
resourceId: EntityIdSchema.optional().describe("ID de la ressource à laquelle rattacher l'action (dependsOn)"),
|
|
830
|
+
contactId: EntityIdSchema.optional().describe("ID du contact auquel rattacher l'action (dependsOn)"),
|
|
831
|
+
opportunityId: EntityIdSchema.optional().describe("ID de l'opportunité à laquelle rattacher l'action (dependsOn)"),
|
|
832
|
+
projectId: EntityIdSchema.optional().describe("ID du projet auquel rattacher l'action (dependsOn)"),
|
|
833
|
+
companyId: EntityIdSchema.optional().describe("ID de la société associée (uniquement en complément d'un contactId)"),
|
|
834
|
+
positioningId: EntityIdSchema.optional().describe("ID du positionnement à lier à l'action (relation positioning). Requis par l'API pour les types d'action liés aux positionnements (ex. RQ) — sans lui, erreur 422 « 1002 - Wrong or missing attribute (/data/relationships/positioning) »."),
|
|
844
835
|
})
|
|
845
836
|
.strict();
|
|
846
837
|
// PUT /actions/{id} (PATCH renvoie 405). Mise à jour partielle des seuls
|
|
@@ -850,7 +841,7 @@ export const ActionCreateSchema = z
|
|
|
850
841
|
// de résolution de libellé, faute d'entité `dependsOn` connue sur l'update).
|
|
851
842
|
export const ActionUpdateSchema = z
|
|
852
843
|
.object({
|
|
853
|
-
id:
|
|
844
|
+
id: EntityIdSchema.describe("ID de l'action à modifier"),
|
|
854
845
|
typeOf: z.coerce
|
|
855
846
|
.number()
|
|
856
847
|
.int()
|
|
@@ -870,7 +861,7 @@ export const ActionUpdateSchema = z
|
|
|
870
861
|
// ---- Timesheet schemas ----
|
|
871
862
|
export const ResourceTimesheetSchema = z
|
|
872
863
|
.object({
|
|
873
|
-
resourceId:
|
|
864
|
+
resourceId: EntityIdSchema.describe("ID de la ressource"),
|
|
874
865
|
month: z.number().int().min(1).max(12).optional().describe("Mois (1-12). Si omis, mois courant."),
|
|
875
866
|
year: z.number().int().min(2000).optional().describe("Année (ex: 2025). Si omis, année courante."),
|
|
876
867
|
})
|
|
@@ -889,28 +880,103 @@ export const TimesheetSearchSchema = z
|
|
|
889
880
|
.regex(/^\d{4}-\d{2}$/)
|
|
890
881
|
.describe("Mois de fin au format YYYY-MM (ex: '2025-03'). Requis."),
|
|
891
882
|
keywords: z.string().optional().describe("Mots-clés (préfixes 'TPS', 'COMP'...)."),
|
|
892
|
-
|
|
893
|
-
|
|
883
|
+
resourceId: EntityIdSchema.optional().describe("Filtrer par ID ressource (référence keywords COMP<id>)"),
|
|
884
|
+
resourceTypes: resourceTypesField,
|
|
885
|
+
validationStates: validationStatesField,
|
|
886
|
+
closed: z.boolean().optional().describe("true = CRA clôturés uniquement, false = non clôturés."),
|
|
887
|
+
...perimeterShape,
|
|
888
|
+
...sortedPaginationShape,
|
|
889
|
+
})
|
|
890
|
+
.strict();
|
|
891
|
+
// ---- Timesheet (CRA) write schemas (issue #249) ----
|
|
892
|
+
//
|
|
893
|
+
// A times report is a monthly container per resource (`term` + `resource`)
|
|
894
|
+
// whose lines live in `regularTimes[]` / `exceptionalTimes[]` — the exact
|
|
895
|
+
// twin of the expenses report (#179). The line shape below is the one the API
|
|
896
|
+
// *returns* (`GET /times-reports/{id}`, `models.time` in the dictionary, and
|
|
897
|
+
// the `plannedTimes` of `/times-reports/default`): `startDate`, `duration`,
|
|
898
|
+
// `workUnitType.reference`, `project`, `delivery`, `batch`. `state` is moved by
|
|
899
|
+
// the validation workflow (`validated`, `waitingForValidation`…) and is not a
|
|
900
|
+
// write field. See CLAUDE.md → *Timesheets* for what was and was not verified
|
|
901
|
+
// against the live API.
|
|
902
|
+
export const TimesheetLineSchema = z
|
|
903
|
+
.object({
|
|
904
|
+
startDate: z
|
|
905
|
+
.string()
|
|
906
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
907
|
+
.describe("Jour saisi (YYYY-MM-DD). Doit tomber dans le mois `term` du CRA."),
|
|
908
|
+
duration: z
|
|
909
|
+
.number()
|
|
910
|
+
.positive()
|
|
911
|
+
.default(1)
|
|
912
|
+
.describe("Durée en unités d'œuvre (jour par défaut : 1 = journée, 0.5 = demi-journée)."),
|
|
913
|
+
workUnitTypeReference: z
|
|
894
914
|
.number()
|
|
895
915
|
.int()
|
|
896
|
-
.
|
|
897
|
-
.
|
|
898
|
-
|
|
899
|
-
|
|
916
|
+
.default(1)
|
|
917
|
+
.describe("Code `reference` du type d'unité d'œuvre — voir `boond_timesheets_default` (`workUnitTypesAllowed` de la ressource). " +
|
|
918
|
+
"1 = « Normale » (production) sur les tenants observés ; les absences (congés, RTT, maladie…) ont leurs propres codes."),
|
|
919
|
+
projectId: EntityIdSchema.optional().describe("ID du projet imputé. Requis pour une activité de production ; absent pour une absence. Couples autorisés : `boond_timesheets_default`."),
|
|
920
|
+
deliveryId: EntityIdSchema.optional().describe("ID de la prestation (delivery) imputée. Requis avec `projectId` pour la production — voir `boond_timesheets_default`."),
|
|
921
|
+
batchId: EntityIdSchema.optional().describe("ID du lot. Absent = aucun lot."),
|
|
922
|
+
})
|
|
923
|
+
.strict();
|
|
924
|
+
export const TimesheetCreateSchema = z
|
|
925
|
+
.object({
|
|
926
|
+
resourceId: EntityIdSchema.describe("ID de la ressource (le collaborateur dont c'est le CRA)."),
|
|
927
|
+
agencyId: EntityIdSchema.optional().describe("ID de l'agence — voir `boond_timesheets_default`. Déduite de la ressource si omise."),
|
|
928
|
+
term: z
|
|
929
|
+
.string()
|
|
930
|
+
.regex(/^\d{4}-\d{2}$/)
|
|
931
|
+
.describe("Mois du CRA (YYYY-MM). Un CRA = un mois × une ressource ; l'API ne déduplique pas."),
|
|
932
|
+
informationComments: z.string().optional().describe("Commentaires du CRA."),
|
|
933
|
+
regularTimes: z
|
|
934
|
+
.array(TimesheetLineSchema)
|
|
935
|
+
.optional()
|
|
936
|
+
.describe("Lignes d'activité normale (production et absences). Omettre pour créer un CRA vide."),
|
|
937
|
+
exceptionalTimes: z
|
|
938
|
+
.array(TimesheetLineSchema)
|
|
939
|
+
.optional()
|
|
940
|
+
.describe("Lignes d'activité exceptionnelle (interventions, astreintes) — types `exceptionalTime` / `exceptionalCalendar`."),
|
|
941
|
+
})
|
|
942
|
+
.strict();
|
|
943
|
+
export const TimesheetUpdateSchema = z
|
|
944
|
+
.object({
|
|
945
|
+
id: EntityIdSchema.describe("ID du CRA à modifier"),
|
|
946
|
+
informationComments: z.string().optional().describe("Commentaires"),
|
|
947
|
+
closed: z.boolean().optional().describe("Clôturer le CRA"),
|
|
948
|
+
regularTimes: z
|
|
949
|
+
.array(TimesheetLineSchema)
|
|
950
|
+
.optional()
|
|
951
|
+
.describe("⚠️ Remplace TOUTES les lignes d'activité normale — envoyer la liste complète (relire le CRA avec `boond_timesheets_get` et fusionner), pas seulement les ajouts."),
|
|
952
|
+
exceptionalTimes: z
|
|
953
|
+
.array(TimesheetLineSchema)
|
|
954
|
+
.optional()
|
|
955
|
+
.describe("⚠️ Remplace TOUTES les lignes d'activité exceptionnelle — même règle que `regularTimes`."),
|
|
956
|
+
})
|
|
957
|
+
.strict();
|
|
958
|
+
export const TimesheetDefaultSchema = z
|
|
959
|
+
.object({
|
|
960
|
+
resourceId: EntityIdSchema.describe("ID de la ressource"),
|
|
961
|
+
term: z
|
|
962
|
+
.string()
|
|
963
|
+
.regex(/^\d{4}-\d{2}$/)
|
|
964
|
+
.describe("Mois du CRA (YYYY-MM)"),
|
|
965
|
+
agencyId: EntityIdSchema.optional().describe("ID de l'agence, si la ressource en a plusieurs"),
|
|
900
966
|
})
|
|
901
967
|
.strict();
|
|
902
968
|
export const TimesheetGetSchema = z
|
|
903
969
|
.object({
|
|
904
|
-
id:
|
|
970
|
+
id: EntityIdSchema.describe("Identifiant unique de la feuille de temps"),
|
|
905
971
|
})
|
|
906
972
|
.strict();
|
|
907
973
|
// ---- Project schemas ----
|
|
908
974
|
export const ProjectCreateSchema = z
|
|
909
975
|
.object({
|
|
910
976
|
name: z.string().min(1).describe("Nom du projet / mission"),
|
|
911
|
-
companyId:
|
|
912
|
-
contactId:
|
|
913
|
-
opportunityId:
|
|
977
|
+
companyId: EntityIdSchema.optional().describe("ID de la société cliente"),
|
|
978
|
+
contactId: EntityIdSchema.optional().describe("ID du contact associé"),
|
|
979
|
+
opportunityId: EntityIdSchema.optional().describe("ID de l'opportunité liée"),
|
|
914
980
|
typeOf: z.number().int().optional().describe("Type de projet (ID du dictionnaire setting.typeOf.project)"),
|
|
915
981
|
state: stateField("project", "État du projet (0=en cours, 1=terminé, 2=archivé...)"),
|
|
916
982
|
startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
|
|
@@ -920,7 +986,7 @@ export const ProjectCreateSchema = z
|
|
|
920
986
|
.strict();
|
|
921
987
|
export const ProjectUpdateSchema = z
|
|
922
988
|
.object({
|
|
923
|
-
id:
|
|
989
|
+
id: EntityIdSchema.describe("ID du projet à modifier"),
|
|
924
990
|
name: z.string().optional().describe("Nom du projet"),
|
|
925
991
|
typeOf: z.number().int().optional().describe("Type de projet (ID du dictionnaire setting.typeOf.project)"),
|
|
926
992
|
state: stateField("project", "État du projet"),
|
|
@@ -933,8 +999,8 @@ export const ProjectUpdateSchema = z
|
|
|
933
999
|
export const InvoiceCreateSchema = z
|
|
934
1000
|
.object({
|
|
935
1001
|
reference: z.string().optional().describe("Référence de la facture"),
|
|
936
|
-
orderId:
|
|
937
|
-
state:
|
|
1002
|
+
orderId: EntityIdSchema.optional().describe("ID du bon de commande associé"),
|
|
1003
|
+
state: stateField("invoice", "État de la facture : ID de `boond://dictionary/states/invoices` (ex: 0 = Création, 1 = Transmis au client)"),
|
|
938
1004
|
invoiceDate: z.string().optional().describe("Date de facturation (YYYY-MM-DD)"),
|
|
939
1005
|
expectedPaymentDate: z.string().optional().describe("Date d'échéance/paiement attendu (YYYY-MM-DD)"),
|
|
940
1006
|
amountExcludingTax: z.number().optional().describe("Montant HT"),
|
|
@@ -946,9 +1012,9 @@ export const InvoiceCreateSchema = z
|
|
|
946
1012
|
.strict();
|
|
947
1013
|
export const InvoiceUpdateSchema = z
|
|
948
1014
|
.object({
|
|
949
|
-
id:
|
|
1015
|
+
id: EntityIdSchema.describe("ID de la facture à modifier"),
|
|
950
1016
|
reference: z.string().optional().describe("Référence de la facture"),
|
|
951
|
-
state:
|
|
1017
|
+
state: stateField("invoice", "État de la facture : ID de `boond://dictionary/states/invoices` (ex: 0 = Création, 1 = Transmis au client)"),
|
|
952
1018
|
invoiceDate: z.string().optional().describe("Date de facturation (YYYY-MM-DD)"),
|
|
953
1019
|
expectedPaymentDate: z.string().optional().describe("Date d'échéance/paiement attendu (YYYY-MM-DD)"),
|
|
954
1020
|
amountExcludingTax: z.number().optional().describe("Montant HT"),
|
|
@@ -958,29 +1024,42 @@ export const InvoiceUpdateSchema = z
|
|
|
958
1024
|
note: z.string().optional().describe("Notes"),
|
|
959
1025
|
})
|
|
960
1026
|
.strict();
|
|
1027
|
+
// Source: resources/invoices/search.raml (filters verified live, issue #248).
|
|
961
1028
|
export const InvoiceSearchSchema = z
|
|
962
1029
|
.object({
|
|
963
1030
|
keywords: z.string().optional().describe("Mots-clés de recherche (référence, société...)"),
|
|
964
|
-
companyId:
|
|
965
|
-
projectId:
|
|
966
|
-
|
|
967
|
-
|
|
1031
|
+
companyId: EntityIdSchema.optional().describe("Filtrer par ID société (référence keywords CSOC<id>)"),
|
|
1032
|
+
projectId: EntityIdSchema.optional().describe("Filtrer par ID projet (référence keywords PRJ<id>)"),
|
|
1033
|
+
contactId: EntityIdSchema.optional().describe("Filtrer par ID contact (référence keywords CCON<id>)"),
|
|
1034
|
+
orderId: EntityIdSchema.optional().describe("Filtrer par ID bon de commande (référence keywords BDC<id>)"),
|
|
1035
|
+
states: intArray("IDs d'états de facture — `boond://dictionary/states/invoices` (ex. impayées = tous les états sauf « payée »)."),
|
|
1036
|
+
projectTypes: projectTypesFilterField,
|
|
1037
|
+
paymentMethods: paymentMethodsField,
|
|
1038
|
+
companies: companiesFilterField,
|
|
1039
|
+
closed: z
|
|
1040
|
+
.boolean()
|
|
1041
|
+
.optional()
|
|
1042
|
+
.describe("true = factures / avoirs clôturés uniquement, false = non clôturés uniquement."),
|
|
1043
|
+
creditNote: z.boolean().optional().describe("true = avoirs uniquement, false = factures uniquement."),
|
|
968
1044
|
period: z
|
|
969
|
-
.
|
|
1045
|
+
.enum(["created", "updated", "expectedPayment", "performedPayment", "period"])
|
|
970
1046
|
.optional()
|
|
971
|
-
.describe("
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1047
|
+
.describe("Champ de date borné par `startDate` / `endDate` : created, updated, expectedPayment (échéance), performedPayment (règlement), period (période facturée, défaut)."),
|
|
1048
|
+
periodDynamic: periodDynamicField,
|
|
1049
|
+
startDate: startDateField,
|
|
1050
|
+
endDate: endDateField,
|
|
1051
|
+
flags: flagsField,
|
|
1052
|
+
...perimeterShape,
|
|
1053
|
+
...sortedPaginationShape,
|
|
975
1054
|
})
|
|
976
1055
|
.strict();
|
|
977
1056
|
// ---- Order schemas (Bons de commande) ----
|
|
978
1057
|
export const OrderCreateSchema = z
|
|
979
1058
|
.object({
|
|
980
1059
|
reference: z.string().optional().describe("Référence du bon de commande"),
|
|
981
|
-
companyId:
|
|
982
|
-
projectId:
|
|
983
|
-
state:
|
|
1060
|
+
companyId: EntityIdSchema.optional().describe("ID de la société"),
|
|
1061
|
+
projectId: EntityIdSchema.optional().describe("ID du projet associé"),
|
|
1062
|
+
state: stateField("order", "État du bon de commande : ID de `boond://dictionary/states/orders`"),
|
|
984
1063
|
orderDate: z.string().optional().describe("Date du bon de commande (YYYY-MM-DD)"),
|
|
985
1064
|
startDate: z.string().optional().describe("Date de début couverte (YYYY-MM-DD)"),
|
|
986
1065
|
endDate: z.string().optional().describe("Date de fin couverte (YYYY-MM-DD)"),
|
|
@@ -992,9 +1071,9 @@ export const OrderCreateSchema = z
|
|
|
992
1071
|
.strict();
|
|
993
1072
|
export const OrderUpdateSchema = z
|
|
994
1073
|
.object({
|
|
995
|
-
id:
|
|
1074
|
+
id: EntityIdSchema.describe("ID du bon de commande à modifier"),
|
|
996
1075
|
reference: z.string().optional().describe("Référence"),
|
|
997
|
-
state:
|
|
1076
|
+
state: stateField("order", "État du bon de commande : ID de `boond://dictionary/states/orders`"),
|
|
998
1077
|
orderDate: z.string().optional().describe("Date (YYYY-MM-DD)"),
|
|
999
1078
|
startDate: z.string().optional().describe("Date de début couverte (YYYY-MM-DD)"),
|
|
1000
1079
|
endDate: z.string().optional().describe("Date de fin couverte (YYYY-MM-DD)"),
|
|
@@ -1004,61 +1083,197 @@ export const OrderUpdateSchema = z
|
|
|
1004
1083
|
note: z.string().optional().describe("Notes"),
|
|
1005
1084
|
})
|
|
1006
1085
|
.strict();
|
|
1086
|
+
// Source: resources/orders/search.raml (filters verified live, issue #248).
|
|
1007
1087
|
export const OrderSearchSchema = z
|
|
1008
1088
|
.object({
|
|
1009
1089
|
keywords: z.string().optional().describe("Mots-clés de recherche"),
|
|
1010
|
-
companyId:
|
|
1011
|
-
projectId:
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1090
|
+
companyId: EntityIdSchema.optional().describe("Filtrer par ID société (référence keywords CSOC<id>)"),
|
|
1091
|
+
projectId: EntityIdSchema.optional().describe("Filtrer par ID projet (référence keywords PRJ<id>)"),
|
|
1092
|
+
contactId: EntityIdSchema.optional().describe("Filtrer par ID contact (référence keywords CCON<id>)"),
|
|
1093
|
+
states: intArray("IDs d'états de bon de commande — `boond://dictionary/states/orders`."),
|
|
1094
|
+
projectTypes: projectTypesFilterField,
|
|
1095
|
+
paymentMethods: paymentMethodsField,
|
|
1096
|
+
companies: companiesFilterField,
|
|
1097
|
+
customerAgreement: z.boolean().optional().describe("true = accord client reçu uniquement, false = sans accord."),
|
|
1098
|
+
exceededOrderedTurnover: z
|
|
1099
|
+
.boolean()
|
|
1100
|
+
.optional()
|
|
1101
|
+
.describe("true = commandes dont le facturé dépasse le montant commandé."),
|
|
1102
|
+
period: z
|
|
1103
|
+
.enum(["created", "updated", "period"])
|
|
1104
|
+
.optional()
|
|
1105
|
+
.describe("Champ de date borné par `startDate` / `endDate` : created, updated, period (période couverte)."),
|
|
1106
|
+
periodDynamic: periodDynamicField,
|
|
1107
|
+
startDate: startDateField,
|
|
1108
|
+
endDate: endDateField,
|
|
1109
|
+
flags: flagsField,
|
|
1110
|
+
...perimeterShape,
|
|
1111
|
+
...sortedPaginationShape,
|
|
1015
1112
|
})
|
|
1016
1113
|
.strict();
|
|
1017
1114
|
// ---- Delivery schemas (Livraisons / CRA) ----
|
|
1115
|
+
// Source: resources/deliveriesGroupments/search.raml — the list route of the
|
|
1116
|
+
// deliveries domain (filters verified live, issue #248).
|
|
1018
1117
|
export const DeliverySearchSchema = z
|
|
1019
1118
|
.object({
|
|
1020
1119
|
keywords: z.string().optional().describe("Mots-clés de recherche"),
|
|
1021
|
-
projectId:
|
|
1022
|
-
companyId:
|
|
1120
|
+
projectId: EntityIdSchema.optional().describe("Filtrer par ID projet (référence keywords PRJ<id>)"),
|
|
1121
|
+
companyId: EntityIdSchema.optional().describe("Filtrer par ID société (référence keywords CSOC<id>)"),
|
|
1122
|
+
resourceId: EntityIdSchema.optional().describe("Filtrer par ID ressource (référence keywords COMP<id>)"),
|
|
1123
|
+
opportunityId: EntityIdSchema.optional().describe("Filtrer par ID opportunité (référence keywords AO<id>)"),
|
|
1124
|
+
projectTypes: projectTypesFilterField,
|
|
1125
|
+
projectStates: intArray("IDs d'états de projet — `boond://dictionary/states/projects`."),
|
|
1126
|
+
deliveryStates: intArray("IDs d'états de prestation — `boond://dictionary/states/deliveries`."),
|
|
1127
|
+
expertiseAreas: strArray("Domaines d'expertise — `boond://dictionary/expertiseAreas`."),
|
|
1128
|
+
transferType: z
|
|
1129
|
+
.enum(["master", "slave", "none", "notSlave", "notMaster", "missing"])
|
|
1130
|
+
.optional()
|
|
1131
|
+
.describe("Filtre sur les transferts de prestation (master / slave / none / notSlave / notMaster / missing)."),
|
|
1132
|
+
period: z
|
|
1133
|
+
.enum(["started", "updated", "stopped", "projectRunning", "running", "hasAdditionalDataOrPurchase"])
|
|
1134
|
+
.optional()
|
|
1135
|
+
.describe("Champ de date borné par `startDate` / `endDate` : started, stopped, updated, running (prestations en cours sur la fenêtre), projectRunning (projet en cours)."),
|
|
1136
|
+
periodDynamic: periodDynamicField,
|
|
1137
|
+
startDate: startDateField,
|
|
1138
|
+
endDate: endDateField,
|
|
1139
|
+
companies: companiesFilterField,
|
|
1140
|
+
flags: flagsField,
|
|
1141
|
+
...perimeterShape,
|
|
1142
|
+
...sortedPaginationShape,
|
|
1143
|
+
})
|
|
1144
|
+
.strict();
|
|
1145
|
+
export const DeliveryCreateSchema = z
|
|
1146
|
+
.object({
|
|
1147
|
+
projectId: EntityIdSchema.describe("ID du projet"),
|
|
1148
|
+
resourceId: EntityIdSchema.describe("ID de la ressource portée par la prestation"),
|
|
1149
|
+
title: z.string().optional().describe("Titre de la prestation/livraison"),
|
|
1150
|
+
typeOf: z.number().int().optional().describe("Type de prestation : ID de `boond://dictionary/typeOf/deliveries`"),
|
|
1151
|
+
state: stateField("delivery", "État de la prestation : ID de `boond://dictionary/states/deliveries`"),
|
|
1023
1152
|
startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
|
|
1024
1153
|
endDate: z.string().optional().describe("Date de fin (YYYY-MM-DD)"),
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1154
|
+
quantity: z.number().optional().describe("Nombre de jours / quantité"),
|
|
1155
|
+
unitPrice: z.number().optional().describe("Prix journalier HT"),
|
|
1156
|
+
averageDailyCost: z.number().optional().describe("Coût journalier moyen"),
|
|
1157
|
+
forceAverageDailyPriceExcludingTax: z.boolean().optional().describe("Forcer le prix journalier HT"),
|
|
1158
|
+
note: z.string().optional().describe("Notes, mappées vers informationComments"),
|
|
1159
|
+
})
|
|
1160
|
+
.strict();
|
|
1161
|
+
// PUT /deliveries/{id} — attributes only, the project / resource attachment
|
|
1162
|
+
// is not moved by an update (issue #252; write path not exercised, see CLAUDE.md).
|
|
1163
|
+
export const DeliveryUpdateSchema = z
|
|
1164
|
+
.object({
|
|
1165
|
+
id: EntityIdSchema.describe("ID de la prestation à modifier"),
|
|
1166
|
+
title: z.string().optional().describe("Titre de la prestation"),
|
|
1167
|
+
typeOf: z.number().int().optional().describe("Type de prestation : ID de `boond://dictionary/typeOf/deliveries`"),
|
|
1168
|
+
state: stateField("delivery", "État de la prestation : ID de `boond://dictionary/states/deliveries`"),
|
|
1169
|
+
startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
|
|
1170
|
+
endDate: z
|
|
1171
|
+
.string()
|
|
1172
|
+
.optional()
|
|
1173
|
+
.describe("Date de fin (YYYY-MM-DD) — prolonger une prestation = repousser cette date"),
|
|
1174
|
+
quantity: z.number().optional().describe("Nombre de jours / quantité (`numberOfDaysInvoicedOrQuantity`)"),
|
|
1175
|
+
unitPrice: z.number().optional().describe("Prix journalier HT (`averageDailyPriceExcludingTax`, forcé)"),
|
|
1176
|
+
averageDailyCost: z.number().optional().describe("Coût journalier moyen"),
|
|
1177
|
+
note: z.string().optional().describe("Notes, mappées vers informationComments"),
|
|
1028
1178
|
})
|
|
1029
1179
|
.strict();
|
|
1030
1180
|
// ---- Absence schemas ----
|
|
1181
|
+
/** `GET /absences-reports/default?resource=&agency=` (issue #257) — the absence types are published there only. */
|
|
1182
|
+
export const AbsenceDefaultSchema = z
|
|
1183
|
+
.object({
|
|
1184
|
+
resourceId: EntityIdSchema.describe("ID de la ressource (requis par l'API)."),
|
|
1185
|
+
agencyId: EntityIdSchema.optional().describe("ID de l'agence — déduite de la ressource si omise."),
|
|
1186
|
+
})
|
|
1187
|
+
.strict();
|
|
1031
1188
|
export const AbsenceCreateSchema = z
|
|
1032
1189
|
.object({
|
|
1033
|
-
resourceId:
|
|
1034
|
-
typeOf: z
|
|
1190
|
+
resourceId: EntityIdSchema.describe("ID de la ressource en absence"),
|
|
1191
|
+
typeOf: z
|
|
1192
|
+
.string()
|
|
1193
|
+
.min(1)
|
|
1194
|
+
.describe("Libellé de l'absence (congé payé, RTT, maladie, sans solde...) — porté par `title` ; le type effectif est `workUnitTypeReference`."),
|
|
1035
1195
|
startDate: z.string().min(1).describe("Date de début (YYYY-MM-DD)"),
|
|
1036
1196
|
endDate: z.string().min(1).describe("Date de fin (YYYY-MM-DD)"),
|
|
1037
1197
|
duration: z.number().optional().describe("Durée en jours ; calculée automatiquement si absente"),
|
|
1038
|
-
workUnitTypeReference: z
|
|
1198
|
+
workUnitTypeReference: z
|
|
1199
|
+
.number()
|
|
1200
|
+
.int()
|
|
1201
|
+
.min(1)
|
|
1202
|
+
.optional()
|
|
1203
|
+
.describe("Code `reference` du type d'absence, publié par `boond_absences_default` (`workUnitTypesAllowed` de la ressource : RTT, maladie, congés payés…) — nulle part ailleurs. Défaut 1 (à confirmer avec le default)."),
|
|
1039
1204
|
absencesPeriods: z.array(z.record(z.string(), z.unknown())).optional().describe("Périodes d'absence Boond brutes"),
|
|
1040
|
-
state
|
|
1205
|
+
// No `state` (issue #250): on `/absences-reports` it is a validation-workflow
|
|
1206
|
+
// string (`waitingForValidation`, `validated`…), not a dictionary integer,
|
|
1207
|
+
// and it is moved by the workflow — same finding as `/expenses-reports`.
|
|
1041
1208
|
note: z.string().optional().describe("Commentaire / motif"),
|
|
1042
1209
|
})
|
|
1043
1210
|
.strict();
|
|
1044
1211
|
export const AbsenceUpdateSchema = z
|
|
1045
1212
|
.object({
|
|
1046
|
-
id:
|
|
1213
|
+
id: EntityIdSchema.describe("ID de l'absence à modifier"),
|
|
1047
1214
|
startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
|
|
1048
1215
|
endDate: z.string().optional().describe("Date de fin (YYYY-MM-DD)"),
|
|
1049
|
-
state: z.number().int().optional().describe("État de la demande"),
|
|
1050
1216
|
note: z.string().optional().describe("Commentaire / motif"),
|
|
1051
1217
|
})
|
|
1052
1218
|
.strict();
|
|
1053
1219
|
export const AbsenceSearchSchema = z
|
|
1054
1220
|
.object({
|
|
1055
1221
|
keywords: z.string().optional().describe("Mots-clés de recherche"),
|
|
1056
|
-
resourceId:
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1222
|
+
resourceId: EntityIdSchema.optional().describe("Filtrer par ID ressource (référence keywords COMP<id>)"),
|
|
1223
|
+
// Both are REQUIRED by `GET /absences-reports` (422 `1017 - Missing required
|
|
1224
|
+
// attribute` otherwise — caught by scripts/smoke-live.mjs, issue #244).
|
|
1225
|
+
// Declaring them optional made the tool fail on its most natural call.
|
|
1226
|
+
startMonth: z
|
|
1227
|
+
.string()
|
|
1228
|
+
.regex(/^\d{4}-\d{2}$/, "Format attendu : YYYY-MM")
|
|
1229
|
+
.describe("Mois de début de période (YYYY-MM) — obligatoire pour l'API"),
|
|
1230
|
+
endMonth: z
|
|
1231
|
+
.string()
|
|
1232
|
+
.regex(/^\d{4}-\d{2}$/, "Format attendu : YYYY-MM")
|
|
1233
|
+
.describe("Mois de fin de période (YYYY-MM) — obligatoire pour l'API"),
|
|
1234
|
+
resourceTypes: resourceTypesField,
|
|
1235
|
+
validationStates: validationStatesField,
|
|
1236
|
+
...perimeterShape,
|
|
1237
|
+
...sortedPaginationShape,
|
|
1238
|
+
})
|
|
1239
|
+
.strict();
|
|
1240
|
+
// ---- Contract search (issue #253) ----
|
|
1241
|
+
// There is no collection GET on `/contracts` (WAF 403 page, the RAML only
|
|
1242
|
+
// documents `post`) and no `/resources/{id}/contracts` tab (404) — probed live
|
|
1243
|
+
// on 2026-09-26. A resource's contracts are only reachable through
|
|
1244
|
+
// `/resources/{id}/administrative` (`included` of type `contract`). This schema
|
|
1245
|
+
// therefore drives a *composed* search: the resource filters select the
|
|
1246
|
+
// resources to scan, the contract filters are applied server-side to what
|
|
1247
|
+
// their administrative tabs return.
|
|
1248
|
+
export const ContractSearchSchema = z
|
|
1249
|
+
.object({
|
|
1250
|
+
resourceId: EntityIdSchema.optional().describe("ID d'une ressource : ne lit que ses contrats (aucune recherche de ressources)."),
|
|
1251
|
+
keywords: z.string().optional().describe("Mots-clés de la recherche de ressources (nom, prénom…)."),
|
|
1252
|
+
resourceStates: intArray("IDs d'états de ressource à parcourir — `boond://dictionary/states/resources`."),
|
|
1253
|
+
resourceTypes: resourceTypesField,
|
|
1254
|
+
...perimeterShape,
|
|
1255
|
+
contractTypes: intArray("IDs de types de contrat à retenir — `boond://dictionary/typeOf/contracts` (CDI, CDD…)."),
|
|
1256
|
+
period: z
|
|
1257
|
+
.enum(["running", "ending", "starting", "probationEnding"])
|
|
1258
|
+
.optional()
|
|
1259
|
+
.describe("Fenêtre `startDate` / `endDate` appliquée côté serveur : running (contrat en cours sur la fenêtre), ending (fin de contrat dans la fenêtre), starting (début dans la fenêtre), probationEnding (fin de période d'essai — `probationEndDate` ou `renewalProbationEndDate` — dans la fenêtre)."),
|
|
1260
|
+
startDate: startDateField,
|
|
1261
|
+
endDate: endDateField,
|
|
1262
|
+
...paginationShape,
|
|
1263
|
+
})
|
|
1264
|
+
.strict();
|
|
1265
|
+
// ---- Validation decision (issue #251) ----
|
|
1266
|
+
// `PUT /validations/{id}` with the workflow state the RAML enumerates on
|
|
1267
|
+
// `validationStates` (`validated` | `rejected`). No RAML documents the write;
|
|
1268
|
+
// the route follows the pattern of every other single-entity PUT and has NOT
|
|
1269
|
+
// been exercised (production tenant) — see CLAUDE.md → *Validations*.
|
|
1270
|
+
export const ValidationDecisionSchema = z
|
|
1271
|
+
.object({
|
|
1272
|
+
id: EntityIdSchema.describe("ID de la validation (ligne de `boond_validations_search`), pas celui du CRA / de la note / de l'absence."),
|
|
1273
|
+
decision: z
|
|
1274
|
+
.enum(["validate", "reject"])
|
|
1275
|
+
.describe("validate → `validated` ; reject → `rejected` (confirmation demandée à l'utilisateur si le client la supporte)."),
|
|
1276
|
+
reason: z.string().optional().describe("Motif, recommandé sur un refus — transmis dans `reason`."),
|
|
1062
1277
|
})
|
|
1063
1278
|
.strict();
|
|
1064
1279
|
// ---- Expense schemas (Notes de frais) ----
|
|
@@ -1128,15 +1343,9 @@ export const ExpenseLineSchema = z
|
|
|
1128
1343
|
.describe("`true` pour un frais kilométrique : renseigner `numberOfKilometers` et omettre `expenseTypeReference`."),
|
|
1129
1344
|
numberOfKilometers: z.number().optional().describe("Nombre de kilomètres (frais kilométrique uniquement)."),
|
|
1130
1345
|
activityType: z.enum(EXPENSE_ACTIVITY_TYPES).default("production").describe("Type d'activité rattachée au frais."),
|
|
1131
|
-
projectId:
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
.describe("ID du projet à imputer. Obligatoire — les couples (projet, prestation) autorisés sont donnés par `boond_expenses_default`."),
|
|
1135
|
-
deliveryId: z
|
|
1136
|
-
.string()
|
|
1137
|
-
.min(1)
|
|
1138
|
-
.describe("ID de la prestation (delivery) à imputer. Obligatoire — voir `boond_expenses_default`."),
|
|
1139
|
-
batchId: z.string().optional().describe("ID du lot. Absent = aucun lot."),
|
|
1346
|
+
projectId: EntityIdSchema.describe("ID du projet à imputer. Obligatoire — les couples (projet, prestation) autorisés sont donnés par `boond_expenses_default`."),
|
|
1347
|
+
deliveryId: EntityIdSchema.describe("ID de la prestation (delivery) à imputer. Obligatoire — voir `boond_expenses_default`."),
|
|
1348
|
+
batchId: EntityIdSchema.optional().describe("ID du lot. Absent = aucun lot."),
|
|
1140
1349
|
reinvoiced: z.boolean().default(false).describe("Frais refacturable au client."),
|
|
1141
1350
|
currency: z.number().int().default(0).describe("ID de devise (`setting.currency`, 0 = EUR)."),
|
|
1142
1351
|
exchangeRate: z.number().default(1).describe("Taux de change vers la devise agence."),
|
|
@@ -1150,11 +1359,8 @@ export const ExpenseLineSchema = z
|
|
|
1150
1359
|
.strict();
|
|
1151
1360
|
export const ExpenseCreateSchema = z
|
|
1152
1361
|
.object({
|
|
1153
|
-
resourceId:
|
|
1154
|
-
agencyId:
|
|
1155
|
-
.string()
|
|
1156
|
-
.optional()
|
|
1157
|
-
.describe("ID de l'agence — voir `boond_expenses_default`. Déduit de la ressource si omis."),
|
|
1362
|
+
resourceId: EntityIdSchema.describe("ID de la ressource (le collaborateur qui a engagé les frais)."),
|
|
1363
|
+
agencyId: EntityIdSchema.optional().describe("ID de l'agence — voir `boond_expenses_default`. Déduit de la ressource si omis."),
|
|
1158
1364
|
term: z
|
|
1159
1365
|
.string()
|
|
1160
1366
|
.regex(/^\d{4}-\d{2}$/)
|
|
@@ -1176,7 +1382,7 @@ export const ExpenseCreateSchema = z
|
|
|
1176
1382
|
.strict();
|
|
1177
1383
|
export const ExpenseUpdateSchema = z
|
|
1178
1384
|
.object({
|
|
1179
|
-
id:
|
|
1385
|
+
id: EntityIdSchema.describe("ID de la note de frais à modifier"),
|
|
1180
1386
|
exchangeRateAgency: z.number().optional().describe("Taux de change agence"),
|
|
1181
1387
|
currencyAgency: z.number().int().optional().describe("ID de devise de l'agence"),
|
|
1182
1388
|
informationComments: z.string().optional().describe("Commentaires"),
|
|
@@ -1192,24 +1398,22 @@ export const ExpenseUpdateSchema = z
|
|
|
1192
1398
|
.strict();
|
|
1193
1399
|
export const ExpenseDefaultSchema = z
|
|
1194
1400
|
.object({
|
|
1195
|
-
resourceId:
|
|
1401
|
+
resourceId: EntityIdSchema.describe("ID de la ressource"),
|
|
1196
1402
|
term: z
|
|
1197
1403
|
.string()
|
|
1198
1404
|
.regex(/^\d{4}-\d{2}$/)
|
|
1199
1405
|
.describe("Mois ciblé (YYYY-MM)"),
|
|
1200
|
-
agencyId:
|
|
1406
|
+
agencyId: EntityIdSchema.optional().describe("ID de l'agence (optionnel — déduit de la ressource)"),
|
|
1201
1407
|
})
|
|
1202
1408
|
.strict();
|
|
1203
1409
|
export const ExpenseSearchSchema = z
|
|
1204
1410
|
.object({
|
|
1205
1411
|
keywords: z.string().optional().describe("Mots-clés de recherche"),
|
|
1206
|
-
resourceId:
|
|
1207
|
-
projectId:
|
|
1412
|
+
resourceId: EntityIdSchema.optional().describe("Filtrer par ID ressource (référence keywords COMP<id>)"),
|
|
1413
|
+
projectId: EntityIdSchema.optional().describe("Filtrer par ID projet (référence keywords PRJ<id>)"),
|
|
1208
1414
|
startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
|
|
1209
1415
|
endDate: z.string().optional().describe("Date de fin (YYYY-MM-DD)"),
|
|
1210
|
-
|
|
1211
|
-
pageSize: z.number().int().min(1).max(MAX_PAGE_SIZE).default(DEFAULT_PAGE_SIZE).describe("Résultats par page"),
|
|
1212
|
-
fields: fieldsField,
|
|
1416
|
+
...paginationShape,
|
|
1213
1417
|
})
|
|
1214
1418
|
.strict();
|
|
1215
1419
|
// ---- Product schemas ----
|
|
@@ -1225,7 +1429,7 @@ export const ProductCreateSchema = z
|
|
|
1225
1429
|
.strict();
|
|
1226
1430
|
export const ProductUpdateSchema = z
|
|
1227
1431
|
.object({
|
|
1228
|
-
id:
|
|
1432
|
+
id: EntityIdSchema.describe("ID du produit à modifier"),
|
|
1229
1433
|
name: z.string().optional().describe("Nom du produit"),
|
|
1230
1434
|
reference: z.string().optional().describe("Référence"),
|
|
1231
1435
|
unitPrice: z.number().optional().describe("Prix unitaire HT"),
|
|
@@ -1237,11 +1441,11 @@ export const ProductUpdateSchema = z
|
|
|
1237
1441
|
// ---- Positioning schemas ----
|
|
1238
1442
|
export const PositioningCreateSchema = z
|
|
1239
1443
|
.object({
|
|
1240
|
-
candidateId:
|
|
1241
|
-
resourceId:
|
|
1242
|
-
projectId:
|
|
1243
|
-
opportunityId:
|
|
1244
|
-
state:
|
|
1444
|
+
candidateId: EntityIdSchema.optional().describe("ID du candidat positionné"),
|
|
1445
|
+
resourceId: EntityIdSchema.optional().describe("ID de la ressource positionnée"),
|
|
1446
|
+
projectId: EntityIdSchema.optional().describe("ID du projet"),
|
|
1447
|
+
opportunityId: EntityIdSchema.optional().describe("ID de l'opportunité"),
|
|
1448
|
+
state: stateField("positioning", "État du positionnement : ID de `boond://dictionary/states/positionings` (`won` rattache le positionnement à un projet)"),
|
|
1245
1449
|
startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
|
|
1246
1450
|
endDate: z.string().optional().describe("Date de fin (YYYY-MM-DD)"),
|
|
1247
1451
|
note: z.string().optional().describe("Notes / commentaires"),
|
|
@@ -1253,61 +1457,403 @@ export const PositioningSearchSchema = z
|
|
|
1253
1457
|
.string()
|
|
1254
1458
|
.optional()
|
|
1255
1459
|
.describe("Mots-clés de recherche. L'API y accepte aussi des références d'entités (AO<id>, CAND<id>, COMP<id>...) — les filtres *Id ci-dessous sont convertis automatiquement en de telles références."),
|
|
1256
|
-
candidateId:
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1460
|
+
candidateId: EntityIdSchema.optional().describe("Filtrer par ID candidat (envoyé à l'API comme référence keywords CAND<id>)"),
|
|
1461
|
+
resourceId: EntityIdSchema.optional().describe("Filtrer par ID ressource (envoyé à l'API comme référence keywords COMP<id>)"),
|
|
1462
|
+
opportunityId: EntityIdSchema.optional().describe("Filtrer par ID opportunité (envoyé à l'API comme référence keywords AO<id>)"),
|
|
1463
|
+
companyId: EntityIdSchema.optional().describe("Filtrer par ID société (envoyé à l'API comme référence keywords CSOC<id>)"),
|
|
1464
|
+
contactId: EntityIdSchema.optional().describe("Filtrer par ID contact (envoyé à l'API comme référence keywords CCON<id>)"),
|
|
1465
|
+
productId: EntityIdSchema.optional().describe("Filtrer par ID produit (envoyé à l'API comme référence keywords PROD<id>)"),
|
|
1466
|
+
...paginationShape,
|
|
1467
|
+
})
|
|
1468
|
+
.strict();
|
|
1469
|
+
// ---- Payment schemas ----
|
|
1470
|
+
// Source: resources/payments/search.raml (filters verified live, issue #248).
|
|
1471
|
+
export const PaymentSearchSchema = z
|
|
1472
|
+
.object({
|
|
1473
|
+
keywords: z.string().optional().describe("Mots-clés de recherche"),
|
|
1474
|
+
purchaseId: EntityIdSchema.optional().describe("Filtrer par ID achat (référence keywords ACH<id>)"),
|
|
1475
|
+
companyId: EntityIdSchema.optional().describe("Filtrer par ID société (référence keywords CSOC<id>)"),
|
|
1476
|
+
projectId: EntityIdSchema.optional().describe("Filtrer par ID projet (référence keywords PRJ<id>)"),
|
|
1477
|
+
resourceId: EntityIdSchema.optional().describe("Filtrer par ID ressource (référence keywords COMP<id>)"),
|
|
1478
|
+
contactId: EntityIdSchema.optional().describe("Filtrer par ID contact (référence keywords CCON<id>)"),
|
|
1479
|
+
paymentStates: intArray("IDs d'états de paiement — `boond://dictionary/states/payments`."),
|
|
1480
|
+
paymentMethods: paymentMethodsField,
|
|
1481
|
+
purchaseTypes: intArray("IDs de types d'achat — `boond://dictionary/typeOf/purchases`."),
|
|
1482
|
+
subscriptionTypes: intArray("IDs de types d'abonnement (`setting.typeOf.subscription` via `boond_application_dictionary`)."),
|
|
1483
|
+
period: z
|
|
1484
|
+
.enum(["created", "updated", "createdPurchase", "subscription", "expected", "performed", "billing"])
|
|
1270
1485
|
.optional()
|
|
1271
|
-
.describe("
|
|
1272
|
-
|
|
1273
|
-
|
|
1486
|
+
.describe("Champ de date borné par `startDate` / `endDate` : expected (échéance), performed (règlement effectif), created, updated, createdPurchase, subscription, billing."),
|
|
1487
|
+
periodDynamic: periodDynamicField,
|
|
1488
|
+
startDate: startDateField,
|
|
1489
|
+
endDate: endDateField,
|
|
1490
|
+
excludeProviderInvoice: z
|
|
1491
|
+
.boolean()
|
|
1274
1492
|
.optional()
|
|
1275
|
-
.describe("
|
|
1276
|
-
|
|
1277
|
-
|
|
1493
|
+
.describe("true = exclure les paiements adossés à une facture fournisseur."),
|
|
1494
|
+
deliveryPurchases: z.boolean().optional().describe("true = paiements des achats liés à une prestation uniquement."),
|
|
1495
|
+
flags: flagsField,
|
|
1496
|
+
...perimeterShape,
|
|
1497
|
+
...sortedPaginationShape,
|
|
1498
|
+
})
|
|
1499
|
+
.strict();
|
|
1500
|
+
export const PaymentCreateSchema = z
|
|
1501
|
+
.object({
|
|
1502
|
+
purchaseId: EntityIdSchema.describe("ID de l'achat réglé"),
|
|
1503
|
+
paymentDate: z.string().optional().describe("Date du paiement (YYYY-MM-DD), mappée vers date"),
|
|
1504
|
+
performedDate: z.string().optional().describe("Date de paiement effectif (YYYY-MM-DD)"),
|
|
1505
|
+
expectedDate: z.string().optional().describe("Date de paiement attendu (YYYY-MM-DD)"),
|
|
1506
|
+
startDate: z.string().optional().describe("Date de début couverte (YYYY-MM-DD)"),
|
|
1507
|
+
endDate: z.string().optional().describe("Date de fin couverte (YYYY-MM-DD)"),
|
|
1508
|
+
amount: z.number().optional().describe("Montant HT du paiement, mappé vers amountExcludingTax"),
|
|
1509
|
+
amountExcludingTax: z.number().optional().describe("Montant HT du paiement"),
|
|
1510
|
+
state: stateField("payment", "État du paiement : ID de `boond://dictionary/states/payments`"),
|
|
1511
|
+
paymentMethod: z.number().int().optional().describe("Mode de paiement : ID de `boond://dictionary/paymentMethods`"),
|
|
1512
|
+
taxRates: z.array(z.number()).optional().describe("Taux de taxes Boond"),
|
|
1513
|
+
reference: z.string().optional().describe("Référence bancaire ou règlement"),
|
|
1514
|
+
note: z.string().optional().describe("Note interne, mappée vers informationComments"),
|
|
1515
|
+
})
|
|
1516
|
+
.strict();
|
|
1517
|
+
// PUT /payments/{id} — issue #252 (write path not exercised, see CLAUDE.md).
|
|
1518
|
+
export const PaymentUpdateSchema = z
|
|
1519
|
+
.object({
|
|
1520
|
+
id: EntityIdSchema.describe("ID du paiement à modifier"),
|
|
1521
|
+
paymentDate: z.string().optional().describe("Date du paiement (YYYY-MM-DD), mappée vers date"),
|
|
1522
|
+
performedDate: z.string().optional().describe("Date de paiement effectif (YYYY-MM-DD) — régulariser un règlement"),
|
|
1523
|
+
expectedDate: z.string().optional().describe("Date de paiement attendu (YYYY-MM-DD)"),
|
|
1524
|
+
startDate: z.string().optional().describe("Date de début couverte (YYYY-MM-DD)"),
|
|
1525
|
+
endDate: z.string().optional().describe("Date de fin couverte (YYYY-MM-DD)"),
|
|
1526
|
+
amount: z.number().optional().describe("Montant HT, mappé vers amountExcludingTax"),
|
|
1527
|
+
amountExcludingTax: z.number().optional().describe("Montant HT"),
|
|
1528
|
+
amountIncludingTax: z.number().optional().describe("Montant TTC"),
|
|
1529
|
+
state: stateField("payment", "État du paiement : ID de `boond://dictionary/states/payments`"),
|
|
1530
|
+
paymentMethod: z.number().int().optional().describe("Mode de paiement : ID de `boond://dictionary/paymentMethods`"),
|
|
1531
|
+
taxRates: z.array(z.number()).optional().describe("Taux de taxes Boond"),
|
|
1532
|
+
reference: z.string().optional().describe("Référence bancaire ou règlement (`number`)"),
|
|
1533
|
+
note: z.string().optional().describe("Note interne, mappée vers informationComments"),
|
|
1534
|
+
})
|
|
1535
|
+
.strict();
|
|
1536
|
+
// ---- Purchase schemas (achats / sous-traitance) ----
|
|
1537
|
+
export const PurchaseSearchSchema = z
|
|
1538
|
+
.object({
|
|
1539
|
+
keywords: z.string().optional().describe("Mots-clés de recherche"),
|
|
1540
|
+
companyId: EntityIdSchema.optional().describe("Filtrer par ID société (référence keywords CSOC<id>)"),
|
|
1541
|
+
projectId: EntityIdSchema.optional().describe("Filtrer par ID projet (référence keywords PRJ<id>)"),
|
|
1542
|
+
...paginationShape,
|
|
1543
|
+
})
|
|
1544
|
+
.strict();
|
|
1545
|
+
export const PurchaseCreateSchema = z
|
|
1546
|
+
.object({
|
|
1547
|
+
title: z.string().optional().describe("Titre de l'achat/sous-traitance"),
|
|
1548
|
+
companyId: EntityIdSchema.optional().describe("ID de la société fournisseur"),
|
|
1549
|
+
contactId: EntityIdSchema.optional().describe("ID du contact fournisseur"),
|
|
1550
|
+
projectId: EntityIdSchema.optional().describe("ID du projet associé"),
|
|
1551
|
+
state: stateField("purchase", "État de l'achat : ID de `boond://dictionary/states/purchases`"),
|
|
1552
|
+
startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
|
|
1553
|
+
endDate: z.string().optional().describe("Date de fin (YYYY-MM-DD)"),
|
|
1554
|
+
note: z.string().optional().describe("Notes / commentaires"),
|
|
1555
|
+
})
|
|
1556
|
+
.strict();
|
|
1557
|
+
// PUT /purchases/{id}/information (RAML `purchases/information.raml`, issue #252).
|
|
1558
|
+
export const PurchaseUpdateSchema = z
|
|
1559
|
+
.object({
|
|
1560
|
+
id: EntityIdSchema.describe("ID de l'achat à modifier"),
|
|
1561
|
+
title: z.string().optional().describe("Titre de l'achat/sous-traitance"),
|
|
1562
|
+
typeOf: z.number().int().optional().describe("Type d'achat : ID de `boond://dictionary/typeOf/purchases`"),
|
|
1563
|
+
state: stateField("purchase", "État de l'achat : ID de `boond://dictionary/states/purchases`"),
|
|
1564
|
+
companyId: EntityIdSchema.optional().describe("ID de la société fournisseur"),
|
|
1565
|
+
contactId: EntityIdSchema.optional().describe("ID du contact fournisseur"),
|
|
1566
|
+
projectId: EntityIdSchema.optional().describe("ID du projet associé"),
|
|
1567
|
+
startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
|
|
1568
|
+
endDate: z.string().optional().describe("Date de fin (YYYY-MM-DD)"),
|
|
1569
|
+
quantity: z.number().optional().describe("Quantité"),
|
|
1570
|
+
amountExcludingTax: z.number().optional().describe("Montant unitaire HT"),
|
|
1571
|
+
taxRate: z.number().optional().describe("Taux de TVA (%) — `boond://dictionary/taxRates`"),
|
|
1572
|
+
paymentMethod: z.number().int().optional().describe("Mode de paiement : ID de `boond://dictionary/paymentMethods`"),
|
|
1573
|
+
paymentTerm: z
|
|
1574
|
+
.number()
|
|
1575
|
+
.int()
|
|
1278
1576
|
.optional()
|
|
1279
|
-
.describe("
|
|
1280
|
-
|
|
1281
|
-
pageSize: z.number().int().min(1).max(MAX_PAGE_SIZE).default(DEFAULT_PAGE_SIZE).describe("Résultats par page"),
|
|
1282
|
-
fields: fieldsField,
|
|
1577
|
+
.describe("Condition de paiement : ID de `boond://dictionary/paymentTerms`"),
|
|
1578
|
+
note: z.string().optional().describe("Notes / commentaires (`informationComments`)"),
|
|
1283
1579
|
})
|
|
1284
1580
|
.strict();
|
|
1285
|
-
// ----
|
|
1286
|
-
export const
|
|
1581
|
+
// ---- Provider invoice schemas (factures fournisseur) ----
|
|
1582
|
+
export const ProviderInvoiceSearchSchema = z
|
|
1287
1583
|
.object({
|
|
1288
1584
|
keywords: z.string().optional().describe("Mots-clés de recherche"),
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1585
|
+
companyId: EntityIdSchema.optional().describe("Filtrer par ID société fournisseur (référence keywords CSOC<id>)"),
|
|
1586
|
+
resourceId: EntityIdSchema.optional().describe("Filtrer par ID ressource (référence keywords COMP<id>)"),
|
|
1587
|
+
...paginationShape,
|
|
1588
|
+
})
|
|
1589
|
+
.strict();
|
|
1590
|
+
export const ProviderInvoiceCreateSchema = z
|
|
1591
|
+
.object({
|
|
1592
|
+
reference: z.string().min(1).describe("Référence de la facture fournisseur"),
|
|
1593
|
+
resourceId: EntityIdSchema.describe("ID de la ressource portée par la facture fournisseur"),
|
|
1594
|
+
companyId: EntityIdSchema.optional().describe("ID de la société fournisseur, mappé vers providerCompany"),
|
|
1595
|
+
contactId: EntityIdSchema.optional().describe("ID du contact fournisseur, mappé vers providerContact"),
|
|
1596
|
+
invoiceDate: z.string().optional().describe("Date de facture (YYYY-MM-DD)"),
|
|
1597
|
+
startDate: z.string().min(1).describe("Date de début de période (YYYY-MM-DD)"),
|
|
1598
|
+
endDate: z.string().min(1).describe("Date de fin de période (YYYY-MM-DD)"),
|
|
1599
|
+
amountExcludingTax: z.number().optional().describe("Montant HT"),
|
|
1600
|
+
amountIncludingTax: z.number().optional().describe("Montant TTC"),
|
|
1601
|
+
currency: z.number().optional().describe("Devise Boond"),
|
|
1602
|
+
exchangeRate: z.number().optional().describe("Taux de change"),
|
|
1603
|
+
currencyAgency: z.number().optional().describe("Devise agence"),
|
|
1604
|
+
exchangeRateAgency: z.number().optional().describe("Taux de change agence"),
|
|
1605
|
+
state: stateField("providerinvoice", "État de la facture fournisseur : ID de `boond://dictionary/states/provider-invoices`"),
|
|
1606
|
+
})
|
|
1607
|
+
.strict();
|
|
1608
|
+
// PUT /provider-invoices/{id} — issue #252 (write path not exercised, see CLAUDE.md).
|
|
1609
|
+
export const ProviderInvoiceUpdateSchema = z
|
|
1610
|
+
.object({
|
|
1611
|
+
id: EntityIdSchema.describe("ID de la facture fournisseur à modifier"),
|
|
1612
|
+
reference: z.string().optional().describe("Référence de la facture fournisseur"),
|
|
1613
|
+
invoiceDate: z.string().optional().describe("Date de facture (YYYY-MM-DD)"),
|
|
1614
|
+
startDate: z.string().optional().describe("Date de début de période (YYYY-MM-DD)"),
|
|
1615
|
+
endDate: z.string().optional().describe("Date de fin de période (YYYY-MM-DD)"),
|
|
1616
|
+
dueDate: z.string().optional().describe("Date d'échéance (YYYY-MM-DD)"),
|
|
1617
|
+
paidDate: z.string().optional().describe("Date de règlement (YYYY-MM-DD) — marquer la facture payée"),
|
|
1618
|
+
amountExcludingTax: z.number().optional().describe("Montant HT"),
|
|
1619
|
+
amountIncludingTax: z.number().optional().describe("Montant TTC"),
|
|
1620
|
+
state: stateField("providerinvoice", "État de la facture fournisseur : ID de `boond://dictionary/states/provider-invoices`"),
|
|
1621
|
+
})
|
|
1622
|
+
.strict();
|
|
1623
|
+
// ---- Contract schemas ----
|
|
1624
|
+
export const ContractCreateSchema = z
|
|
1625
|
+
.object({
|
|
1626
|
+
resourceId: EntityIdSchema.optional().describe("ID de la ressource associée"),
|
|
1627
|
+
typeOf: z
|
|
1628
|
+
.number()
|
|
1629
|
+
.int()
|
|
1630
|
+
.optional()
|
|
1631
|
+
.describe("Type de contrat : ID entier du dictionnaire `setting.typeOf.contract` (CDI, CDD, freelance…), via `boond_application_dictionary`"),
|
|
1294
1632
|
startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
|
|
1295
1633
|
endDate: z.string().optional().describe("Date de fin (YYYY-MM-DD)"),
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1634
|
+
note: z.string().optional().describe("Notes / commentaires (`informationComments`)"),
|
|
1635
|
+
})
|
|
1636
|
+
.strict();
|
|
1637
|
+
// PUT /contracts/{id} — issue #252 (write path not exercised, see CLAUDE.md).
|
|
1638
|
+
export const ContractUpdateSchema = z
|
|
1639
|
+
.object({
|
|
1640
|
+
id: EntityIdSchema.describe("ID du contrat à modifier"),
|
|
1641
|
+
typeOf: z.number().int().optional().describe("Type de contrat : ID de `boond://dictionary/typeOf/contracts`"),
|
|
1642
|
+
startDate: z.string().optional().describe("Date de début (YYYY-MM-DD)"),
|
|
1643
|
+
endDate: z.string().optional().describe("Date de fin (YYYY-MM-DD) — prolonger un CDD = repousser cette date"),
|
|
1644
|
+
endReason: z.number().int().optional().describe("Motif de fin : ID de `boond://dictionary/contractEndReasons`"),
|
|
1645
|
+
probationEndDate: z.string().optional().describe("Fin de période d'essai initiale (YYYY-MM-DD)"),
|
|
1646
|
+
renewalProbationEndDate: z.string().optional().describe("Fin de période d'essai renouvelée (YYYY-MM-DD)"),
|
|
1647
|
+
monthlySalary: z.number().optional().describe("Salaire mensuel"),
|
|
1648
|
+
annualSalary: z.number().optional().describe("Salaire annuel"),
|
|
1649
|
+
numberOfWorkingDays: z.number().optional().describe("Nombre de jours ouvrés annuel"),
|
|
1650
|
+
note: z.string().optional().describe("Notes / commentaires (`informationComments`)"),
|
|
1299
1651
|
})
|
|
1300
1652
|
.strict();
|
|
1301
1653
|
// ---- Advantage schemas ----
|
|
1654
|
+
// `GET /advantages` does not exist (the RAML only has POST there, and the live
|
|
1655
|
+
// API answers with a WAF 403 page); advantages are listed per resource via
|
|
1656
|
+
// `GET /resources/{id}/advantages` (issue #247). Hence a required `resourceId`.
|
|
1302
1657
|
export const AdvantageSearchSchema = z
|
|
1303
1658
|
.object({
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
pageSize: z.number().int().min(1).max(MAX_PAGE_SIZE).default(DEFAULT_PAGE_SIZE).describe("Résultats par page"),
|
|
1308
|
-
fields: fieldsField,
|
|
1659
|
+
resourceId: EntityIdSchema.describe("ID de la ressource dont on liste les avantages (route /resources/{id}/advantages)"),
|
|
1660
|
+
advantageTypes: strArray("Types d'avantage à conserver, au format `<reference>_<agencyId>` (référence du type + ID d'agence, ex: '2_1')."),
|
|
1661
|
+
...paginationShape,
|
|
1309
1662
|
})
|
|
1310
1663
|
.strict();
|
|
1664
|
+
// ---- Flags, attached flags, tasks, todolists, advantages writes (issue #254) ----
|
|
1665
|
+
/** Entities that carry `attachedFlags.raml` (11) — the query-parameter name of `DELETE /attached-flags` is the entity's singular. */
|
|
1666
|
+
export const ATTACHED_FLAG_ENTITIES = [
|
|
1667
|
+
"candidate",
|
|
1668
|
+
"resource",
|
|
1669
|
+
"contact",
|
|
1670
|
+
"company",
|
|
1671
|
+
"opportunity",
|
|
1672
|
+
"project",
|
|
1673
|
+
"order",
|
|
1674
|
+
"product",
|
|
1675
|
+
"purchase",
|
|
1676
|
+
"action",
|
|
1677
|
+
"positioning",
|
|
1678
|
+
"invoice",
|
|
1679
|
+
];
|
|
1680
|
+
/** Entities that carry `tasks.raml` (14). */
|
|
1681
|
+
export const TASK_ENTITIES = [
|
|
1682
|
+
"candidate",
|
|
1683
|
+
"resource",
|
|
1684
|
+
"contact",
|
|
1685
|
+
"company",
|
|
1686
|
+
"opportunity",
|
|
1687
|
+
"project",
|
|
1688
|
+
"order",
|
|
1689
|
+
"product",
|
|
1690
|
+
"purchase",
|
|
1691
|
+
"positioning",
|
|
1692
|
+
"invoice",
|
|
1693
|
+
"contract",
|
|
1694
|
+
"delivery",
|
|
1695
|
+
"payment",
|
|
1696
|
+
"form",
|
|
1697
|
+
];
|
|
1698
|
+
export const FlagCreateSchema = z
|
|
1699
|
+
.object({
|
|
1700
|
+
name: z.string().min(1).describe("Libellé du drapeau (ex. « vivier Java Q4 »)."),
|
|
1701
|
+
mainManagerId: EntityIdSchema.optional().describe("ID de la ressource responsable du drapeau — l'utilisateur courant si omis."),
|
|
1702
|
+
})
|
|
1703
|
+
.strict();
|
|
1704
|
+
export const AttachedFlagsListSchema = z
|
|
1705
|
+
.object({
|
|
1706
|
+
entity: z.enum(ATTACHED_FLAG_ENTITIES).describe("Type de l'enregistrement."),
|
|
1707
|
+
id: EntityIdSchema.describe("ID numérique de l'enregistrement."),
|
|
1708
|
+
})
|
|
1709
|
+
.strict();
|
|
1710
|
+
export const AttachedFlagSchema = AttachedFlagsListSchema.extend({
|
|
1711
|
+
flagId: EntityIdSchema.describe("ID du drapeau (`boond_flags_search`)."),
|
|
1712
|
+
}).strict();
|
|
1713
|
+
export const TasksGetSchema = z
|
|
1714
|
+
.object({
|
|
1715
|
+
entity: z.enum(TASK_ENTITIES).describe("Type de l'enregistrement."),
|
|
1716
|
+
id: EntityIdSchema.describe("ID numérique de l'enregistrement."),
|
|
1717
|
+
})
|
|
1718
|
+
.strict();
|
|
1719
|
+
const TodolistTaskSchema = z
|
|
1720
|
+
.object({
|
|
1721
|
+
description: z.string().min(1).describe("Intitulé de la tâche."),
|
|
1722
|
+
row: z.number().int().min(0).optional().describe("Ordre d'affichage."),
|
|
1723
|
+
state: z.number().int().optional().describe("État (0 = à faire par défaut)."),
|
|
1724
|
+
})
|
|
1725
|
+
.strict();
|
|
1726
|
+
// POST /todolists from `models.todolist` (title, state, profile, profileTypesOf,
|
|
1727
|
+
// profileStates, agencies, tasks) — the RAML documents no body; not exercised.
|
|
1728
|
+
export const TodolistCreateSchema = z
|
|
1729
|
+
.object({
|
|
1730
|
+
title: z.string().min(1).describe("Titre de la todolist."),
|
|
1731
|
+
profile: z
|
|
1732
|
+
.string()
|
|
1733
|
+
.optional()
|
|
1734
|
+
.describe("Fiche sur laquelle la liste s'applique (ex. candidate, resource, opportunity…)."),
|
|
1735
|
+
profileTypesOf: z.array(z.number().int()).optional().describe("Types de fiche concernés (IDs de dictionnaire)."),
|
|
1736
|
+
profileStates: z.array(z.number().int()).optional().describe("États de fiche concernés (IDs de dictionnaire)."),
|
|
1737
|
+
agencyIds: z.array(EntityIdSchema).optional().describe("Agences concernées (IDs)."),
|
|
1738
|
+
tasks: z.array(TodolistTaskSchema).min(1).describe("Tâches de la liste, dans l'ordre."),
|
|
1739
|
+
})
|
|
1740
|
+
.strict();
|
|
1741
|
+
/** `GET /advantages/default?resource=&contract=&project=&delivery=` (RAML `advantages/default.raml`). */
|
|
1742
|
+
export const AdvantageDefaultSchema = z
|
|
1743
|
+
.object({
|
|
1744
|
+
resourceId: EntityIdSchema.describe("ID de la ressource bénéficiaire."),
|
|
1745
|
+
contractId: EntityIdSchema.optional().describe("ID du contrat de rattachement."),
|
|
1746
|
+
projectId: EntityIdSchema.optional().describe("ID du projet (avantage refacturable)."),
|
|
1747
|
+
deliveryId: EntityIdSchema.optional().describe("ID de la prestation."),
|
|
1748
|
+
})
|
|
1749
|
+
.strict();
|
|
1750
|
+
// POST /advantages from `models.advantage`; the RAML documents no body — not exercised.
|
|
1751
|
+
export const AdvantageCreateSchema = z
|
|
1752
|
+
.object({
|
|
1753
|
+
resourceId: EntityIdSchema.describe("ID de la ressource bénéficiaire (relation `resource`, requise)."),
|
|
1754
|
+
advantageType: z
|
|
1755
|
+
.union([z.number().int(), z.string().min(1)])
|
|
1756
|
+
.describe("Type d'avantage : `reference` ou `<reference>_<agencyId>` tel que publié par `boond_advantages_default` (`advantageTypes`)."),
|
|
1757
|
+
date: z
|
|
1758
|
+
.string()
|
|
1759
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
1760
|
+
.describe("Date de l'avantage (YYYY-MM-DD)."),
|
|
1761
|
+
returnDate: z
|
|
1762
|
+
.string()
|
|
1763
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
1764
|
+
.optional()
|
|
1765
|
+
.describe("Date de restitution (véhicule, matériel)."),
|
|
1766
|
+
quantity: z.number().optional().describe("Quantité (ex. nombre de tickets)."),
|
|
1767
|
+
participationAmount: z.number().optional().describe("Participation salarié."),
|
|
1768
|
+
employeeAmount: z.number().optional().describe("Montant versé au salarié."),
|
|
1769
|
+
agencyAmount: z.number().optional().describe("Charges / coefficient de charge côté agence."),
|
|
1770
|
+
contractId: EntityIdSchema.optional().describe("ID du contrat de rattachement."),
|
|
1771
|
+
projectId: EntityIdSchema.optional().describe("ID du projet à refacturer."),
|
|
1772
|
+
deliveryId: EntityIdSchema.optional().describe("ID de la prestation."),
|
|
1773
|
+
note: z.string().optional().describe("Commentaires (`informationComments`)."),
|
|
1774
|
+
})
|
|
1775
|
+
.strict();
|
|
1776
|
+
// ---- Inactivities, forms, groupments (issue #256) ----
|
|
1777
|
+
// All three collections document `post` only (no list GET), plus `default`
|
|
1778
|
+
// and `rights`; bodies come from `models.*` in the dictionary and were not
|
|
1779
|
+
// exercised (production tenant). Detail reads follow the `/{collection}/{id}`
|
|
1780
|
+
// pattern of every other entity.
|
|
1781
|
+
const isoDate = (doc) => z
|
|
1782
|
+
.string()
|
|
1783
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
1784
|
+
.describe(doc);
|
|
1785
|
+
export const InactivityDefaultSchema = z
|
|
1786
|
+
.object({
|
|
1787
|
+
resourceId: EntityIdSchema.describe("ID de la ressource (requis par `GET /inactivities/default`)."),
|
|
1788
|
+
})
|
|
1789
|
+
.strict();
|
|
1790
|
+
export const InactivityCreateSchema = z
|
|
1791
|
+
.object({
|
|
1792
|
+
resourceId: EntityIdSchema.describe("ID de la ressource en intercontrat / inactivité (relation `resource`, requise)."),
|
|
1793
|
+
title: z.string().optional().describe("Intitulé (ex. « Intercontrat », « Formation interne »)."),
|
|
1794
|
+
inactivityType: z
|
|
1795
|
+
.union([z.number().int(), z.string().min(1)])
|
|
1796
|
+
.optional()
|
|
1797
|
+
.describe("Type d'inactivité tel que publié par `boond_inactivities_default`."),
|
|
1798
|
+
startDate: isoDate("Date de début (YYYY-MM-DD)."),
|
|
1799
|
+
endDate: isoDate("Date de fin (YYYY-MM-DD)."),
|
|
1800
|
+
numberOfDaysInvoicedOrQuantity: z.number().optional().describe("Nombre de jours de la période."),
|
|
1801
|
+
averageDailyCost: z.number().optional().describe("Coût journalier moyen retenu."),
|
|
1802
|
+
contractId: EntityIdSchema.optional().describe("ID du contrat de rattachement."),
|
|
1803
|
+
note: z.string().optional().describe("Commentaires (`informationComments`)."),
|
|
1804
|
+
})
|
|
1805
|
+
.strict();
|
|
1806
|
+
export const FormDefaultSchema = z
|
|
1807
|
+
.object({
|
|
1808
|
+
templateId: EntityIdSchema.describe("ID du modèle de formulaire (`template`)."),
|
|
1809
|
+
resourceId: EntityIdSchema.describe("ID de l'entité visée par le formulaire (`resource`)."),
|
|
1810
|
+
})
|
|
1811
|
+
.strict();
|
|
1812
|
+
export const FormCreateSchema = z
|
|
1813
|
+
.object({
|
|
1814
|
+
templateId: EntityIdSchema.describe("ID du modèle de formulaire (relation `template`, requise)."),
|
|
1815
|
+
resourceId: EntityIdSchema.optional().describe("Ressource visée (relation `dependsOn`, type resource)."),
|
|
1816
|
+
candidateId: EntityIdSchema.optional().describe("Candidat visé (relation `dependsOn`, type candidate)."),
|
|
1817
|
+
validatorId: EntityIdSchema.optional().describe("Ressource qui validera le formulaire (`validator`)."),
|
|
1818
|
+
recipientId: EntityIdSchema.optional().describe("Ressource destinataire (`recipient`)."),
|
|
1819
|
+
validateDate: isoDate("Date de validation souhaitée (YYYY-MM-DD).").optional(),
|
|
1820
|
+
remindDate: isoDate("Date de rappel (YYYY-MM-DD).").optional(),
|
|
1821
|
+
})
|
|
1822
|
+
.strict();
|
|
1823
|
+
export const GroupmentDefaultSchema = z
|
|
1824
|
+
.object({
|
|
1825
|
+
projectId: EntityIdSchema.describe("ID du projet (requis par `GET /groupments/default`)."),
|
|
1826
|
+
})
|
|
1827
|
+
.strict();
|
|
1828
|
+
const groupmentWritableShape = {
|
|
1829
|
+
title: z.string().optional().describe("Titre du regroupement."),
|
|
1830
|
+
startDate: isoDate("Date de début (YYYY-MM-DD).").optional(),
|
|
1831
|
+
endDate: isoDate("Date de fin (YYYY-MM-DD).").optional(),
|
|
1832
|
+
averageDailyPriceExcludingTax: z.number().optional().describe("Prix journalier HT du regroupement."),
|
|
1833
|
+
forceAverageDailyPriceExcludingTax: z.boolean().optional().describe("Forcer le prix journalier."),
|
|
1834
|
+
averageDailyCost: z.number().optional().describe("Coût journalier moyen."),
|
|
1835
|
+
numberOfDaysInvoicedOrQuantity: z.number().optional().describe("Jours / quantité facturés."),
|
|
1836
|
+
numberOfDaysFree: z.number().optional().describe("Jours offerts."),
|
|
1837
|
+
deliveryIds: z.array(EntityIdSchema).optional().describe("Prestations regroupées (relation `deliveries`)."),
|
|
1838
|
+
note: z.string().optional().describe("Commentaires (`informationComments`)."),
|
|
1839
|
+
};
|
|
1840
|
+
export const GroupmentCreateSchema = z
|
|
1841
|
+
.object({
|
|
1842
|
+
projectId: EntityIdSchema.describe("ID du projet (relation `project`, requise)."),
|
|
1843
|
+
...groupmentWritableShape,
|
|
1844
|
+
})
|
|
1845
|
+
.strict();
|
|
1846
|
+
export const GroupmentUpdateSchema = z
|
|
1847
|
+
.object({
|
|
1848
|
+
id: EntityIdSchema.describe("ID du regroupement à modifier."),
|
|
1849
|
+
...groupmentWritableShape,
|
|
1850
|
+
})
|
|
1851
|
+
.strict();
|
|
1852
|
+
// ---- Alerts (issue #255) ----
|
|
1853
|
+
// `GET /alerts` ("Search alerts for user dashboard") documents no parameter at
|
|
1854
|
+
// all — not even the searchable / paginable traits — so the tool takes only
|
|
1855
|
+
// the client-side projection.
|
|
1856
|
+
export const AlertSearchSchema = z.object({ fields: fieldsField }).strict();
|
|
1311
1857
|
// ---- Application schemas ----
|
|
1312
1858
|
// ---- Validation schemas ----
|
|
1313
1859
|
// `/validations` requires `startMonth` + `endMonth` (YYYY-MM). Optional filters
|
|
@@ -1339,15 +1885,7 @@ export const ValidationSearchSchema = z
|
|
|
1339
1885
|
.optional()
|
|
1340
1886
|
.describe("États de validation."),
|
|
1341
1887
|
validationAlerts: z.boolean().optional().describe("Filtrer sur les validations avec alertes."),
|
|
1342
|
-
|
|
1343
|
-
pageSize: z
|
|
1344
|
-
.number()
|
|
1345
|
-
.int()
|
|
1346
|
-
.min(1)
|
|
1347
|
-
.max(MAX_PAGE_SIZE)
|
|
1348
|
-
.default(DEFAULT_PAGE_SIZE)
|
|
1349
|
-
.describe(`Nombre de résultats par page (max: ${MAX_PAGE_SIZE}, défaut: ${DEFAULT_PAGE_SIZE})`),
|
|
1350
|
-
fields: fieldsField,
|
|
1888
|
+
...paginationShape,
|
|
1351
1889
|
})
|
|
1352
1890
|
.strict();
|
|
1353
1891
|
// ---- Notification schemas ----
|
|
@@ -1364,15 +1902,7 @@ export const NotificationSearchSchema = z
|
|
|
1364
1902
|
.array(z.string())
|
|
1365
1903
|
.optional()
|
|
1366
1904
|
.describe("Types de modules parents (ex: 'contract', 'global', 'project'...)."),
|
|
1367
|
-
|
|
1368
|
-
pageSize: z
|
|
1369
|
-
.number()
|
|
1370
|
-
.int()
|
|
1371
|
-
.min(1)
|
|
1372
|
-
.max(MAX_PAGE_SIZE)
|
|
1373
|
-
.default(DEFAULT_PAGE_SIZE)
|
|
1374
|
-
.describe(`Nombre de résultats par page (max: ${MAX_PAGE_SIZE}, défaut: ${DEFAULT_PAGE_SIZE})`),
|
|
1375
|
-
fields: fieldsField,
|
|
1905
|
+
...paginationShape,
|
|
1376
1906
|
})
|
|
1377
1907
|
.strict();
|
|
1378
1908
|
// ---- Reporting schemas ----
|
|
@@ -1546,7 +2076,7 @@ export const DictionaryGetSchema = z
|
|
|
1546
2076
|
dictionaryType: z
|
|
1547
2077
|
.string()
|
|
1548
2078
|
.min(1)
|
|
1549
|
-
.describe("
|
|
2079
|
+
.describe("Chemin dotté relatif à `data` de /application/dictionary (ex: setting.state.resource, setting.typeOf.project, setting.action.candidate, setting.tool, country, languages). La forme « states/resources » (slash) n'est pas valide."),
|
|
1550
2080
|
})
|
|
1551
2081
|
.strict();
|
|
1552
2082
|
// ---- Documents ----
|