@deveye/types 0.15.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 +21 -0
- package/README.md +23 -0
- package/package.json +68 -0
- package/src/domain/audience.ts +549 -0
- package/src/domain/backup.ts +355 -0
- package/src/domain/credential.ts +55 -0
- package/src/domain/database.ts +467 -0
- package/src/domain/deploy.ts +231 -0
- package/src/domain/device.ts +172 -0
- package/src/domain/deviceFiles.ts +84 -0
- package/src/domain/deviceLogs.ts +82 -0
- package/src/domain/featureRegistry.ts +392 -0
- package/src/domain/finance.ts +477 -0
- package/src/domain/git.ts +419 -0
- package/src/domain/home.ts +314 -0
- package/src/domain/live.ts +272 -0
- package/src/domain/logs.ts +117 -0
- package/src/domain/mail.ts +394 -0
- package/src/domain/metrics.ts +127 -0
- package/src/domain/note.ts +202 -0
- package/src/domain/notifications.ts +268 -0
- package/src/domain/packages.ts +35 -0
- package/src/domain/password.ts +36 -0
- package/src/domain/presence.ts +21 -0
- package/src/domain/project.ts +168 -0
- package/src/domain/projectBoard.ts +130 -0
- package/src/domain/projectChat.ts +46 -0
- package/src/domain/projectHistory.ts +82 -0
- package/src/domain/projectLink.ts +87 -0
- package/src/domain/projectPlan.ts +68 -0
- package/src/domain/report.ts +492 -0
- package/src/domain/role.ts +8 -0
- package/src/domain/secrecy.ts +66 -0
- package/src/domain/sentinel.ts +623 -0
- package/src/domain/sharing.ts +186 -0
- package/src/domain/syncProtocol.ts +116 -0
- package/src/domain/twoFactor.ts +40 -0
- package/src/domain/uptime.ts +216 -0
- package/src/domain/user.ts +141 -0
- package/src/domain/workspace.ts +56 -0
- package/src/domain/workspaceRole.ts +251 -0
- package/src/features/admin.ts +112 -0
- package/src/features/audience.ts +275 -0
- package/src/features/backup.ts +230 -0
- package/src/features/database.ts +461 -0
- package/src/features/deploy.ts +245 -0
- package/src/features/device.ts +292 -0
- package/src/features/deviceFiles.ts +83 -0
- package/src/features/deviceLogs.ts +36 -0
- package/src/features/deviceTerminal.ts +57 -0
- package/src/features/finance.ts +360 -0
- package/src/features/git.ts +368 -0
- package/src/features/home.ts +32 -0
- package/src/features/live.ts +113 -0
- package/src/features/logs.ts +86 -0
- package/src/features/mail.ts +374 -0
- package/src/features/metrics.ts +185 -0
- package/src/features/note.ts +189 -0
- package/src/features/notify.ts +164 -0
- package/src/features/password.ts +67 -0
- package/src/features/project.ts +709 -0
- package/src/features/registry.ts +103 -0
- package/src/features/secrecy.ts +120 -0
- package/src/features/sentinel.ts +233 -0
- package/src/features/sharing.ts +79 -0
- package/src/features/twoFactor.ts +47 -0
- package/src/features/uptime.ts +186 -0
- package/src/features/user.ts +91 -0
- package/src/features/workspace.ts +200 -0
- package/src/http/auth.ts +94 -0
- package/src/http/device.ts +222 -0
- package/src/http/status.ts +45 -0
- package/src/index.ts +1700 -0
- package/src/protocol/agent.ts +1171 -0
- package/src/protocol/envelope.ts +46 -0
- package/src/protocol/error.ts +27 -0
- package/src/protocol/result.ts +17 -0
- package/src/protocol/version.ts +6 -0
- package/src/sdk/client-ambient.d.ts +238 -0
- package/src/sdk/client.ts +66 -0
- package/src/sdk/ids.ts +25 -0
- package/src/sdk/index.ts +11 -0
- package/src/sdk/manifest.ts +326 -0
- package/src/sdk/providers.ts +48 -0
- package/src/sdk/server.ts +378 -0
- package/src/sdk/testing.ts +179 -0
- package/src/utils/version.ts +28 -0
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Finances: le grand livre d'un espace, pour un particulier comme pour une PME.
|
|
5
|
+
*
|
|
6
|
+
* ## Les montants sont des entiers de centimes
|
|
7
|
+
*
|
|
8
|
+
* Jamais un flottant, nulle part: ni en base, ni sur le fil, ni dans le client.
|
|
9
|
+
* `0.1 + 0.2 !== 0.3` est une curiosité amusante partout sauf sur un solde, où
|
|
10
|
+
* l'écart s'accumule silencieusement à chaque écriture jusqu'à ce que la somme
|
|
11
|
+
* des opérations ne retombe plus sur le solde affiché. Le formatage en devise
|
|
12
|
+
* est la toute dernière étape, faite à l'affichage seul.
|
|
13
|
+
*
|
|
14
|
+
* ## Les dates sont des jours, pas des instants
|
|
15
|
+
*
|
|
16
|
+
* Une opération appartient à un jour civil (`AAAA-MM-JJ`), pas à un instant.
|
|
17
|
+
* Un horodatage epoch se décalerait d'un fuseau à l'autre et ferait basculer une
|
|
18
|
+
* dépense du 31 janvier au 1er février selon qui la regarde, ce qui déplacerait
|
|
19
|
+
* un mois comptable entier. La colonne SQL est un `DATE`, et la chaîne voyage
|
|
20
|
+
* telle quelle.
|
|
21
|
+
*
|
|
22
|
+
* ## Ce qui est chiffré, et ce qui ne peut pas l'être
|
|
23
|
+
*
|
|
24
|
+
* Le chiffrement de DevEye est non déterministe: rien de ce sur quoi on agrège
|
|
25
|
+
* ne peut le traverser. Un solde, un budget et une répartition par catégorie
|
|
26
|
+
* sont des `SUM(...) GROUP BY`, donc les **nombres, dates et rattachements**
|
|
27
|
+
* restent en clair, et le **texte libre** (intitulé, tiers, note, nom de compte,
|
|
28
|
+
* nom de catégorie) est chiffré. C'est le même partage que l'audience, et pour
|
|
29
|
+
* la même raison: sans lui, calculer un solde imposerait de télécharger toutes
|
|
30
|
+
* les opérations depuis le début dans le navigateur.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** Plafond d'un montant, en centimes: mille milliards d'unités. */
|
|
34
|
+
export const FINANCE_AMOUNT_MAX = 100_000_000_000_000;
|
|
35
|
+
|
|
36
|
+
export const FINANCE_LABEL_MAX_LENGTH = 160;
|
|
37
|
+
export const FINANCE_NAME_MAX_LENGTH = 80;
|
|
38
|
+
export const FINANCE_NOTE_MAX_LENGTH = 2_000;
|
|
39
|
+
export const FINANCE_COUNTERPARTY_MAX_LENGTH = 120;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Un montant, en centimes, toujours **positif**. Le sens (entrée ou sortie) est
|
|
43
|
+
* porté par le `kind` de l'opération et non par le signe: un montant signé
|
|
44
|
+
* laisse exister « une dépense de -30 € », qui est une recette écrite de
|
|
45
|
+
* travers, et oblige chaque écran à se demander ce qu'il regarde.
|
|
46
|
+
*/
|
|
47
|
+
export const financeAmountSchema = z.number().int().nonnegative().max(FINANCE_AMOUNT_MAX);
|
|
48
|
+
|
|
49
|
+
/** Un solde, lui, est signé: un compte peut être à découvert. */
|
|
50
|
+
export const financeBalanceSchema = z
|
|
51
|
+
.number()
|
|
52
|
+
.int()
|
|
53
|
+
.min(-FINANCE_AMOUNT_MAX)
|
|
54
|
+
.max(FINANCE_AMOUNT_MAX);
|
|
55
|
+
|
|
56
|
+
/** Un jour civil, `AAAA-MM-JJ`. */
|
|
57
|
+
export const financeDateSchema = z
|
|
58
|
+
.string()
|
|
59
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Date attendue au format AAAA-MM-JJ');
|
|
60
|
+
|
|
61
|
+
/** Un mois civil, `AAAA-MM`, tel que le rendent les séries du tableau de bord. */
|
|
62
|
+
export const financeMonthSchema = z.string().regex(/^\d{4}-\d{2}$/);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Palette nommée des comptes et des catégories, adossée aux jetons de thème
|
|
66
|
+
* `--finance-<nom>`. Nommée plutôt que libre en hexadécimal: la valeur stockée
|
|
67
|
+
* reste liée au thème, donc elle suit ses réglages au lieu de jurer avec eux le
|
|
68
|
+
* jour où la palette est retouchée. Élargir cet enum ajoute une couleur.
|
|
69
|
+
*/
|
|
70
|
+
export const financeColorSchema = z.enum([
|
|
71
|
+
'red',
|
|
72
|
+
'orange',
|
|
73
|
+
'yellow',
|
|
74
|
+
'green',
|
|
75
|
+
'blue',
|
|
76
|
+
'indigo',
|
|
77
|
+
'purple',
|
|
78
|
+
'pink'
|
|
79
|
+
]);
|
|
80
|
+
export type FinanceColor = z.infer<typeof financeColorSchema>;
|
|
81
|
+
|
|
82
|
+
export const FINANCE_COLORS = financeColorSchema.options;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Devise de l'espace, code ISO 4217. Une seule par espace, et c'est délibéré:
|
|
86
|
+
* le multidevise n'est pas un champ de plus mais un taux de change daté par
|
|
87
|
+
* opération, sans quoi tout total additionnerait des euros et des dollars.
|
|
88
|
+
*/
|
|
89
|
+
export const financeCurrencySchema = z.string().regex(/^[A-Z]{3}$/);
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Réglages de la feature pour l'espace.
|
|
93
|
+
*
|
|
94
|
+
* `vatEnabled` est le seul commutateur entre l'usage particulier et l'usage
|
|
95
|
+
* PME: il fait apparaître la TVA sur les opérations et le récapitulatif
|
|
96
|
+
* collectée / déductible du tableau de bord. Rien d'autre ne change, parce que
|
|
97
|
+
* rien d'autre n'a besoin de changer: un livre de comptes est le même objet des
|
|
98
|
+
* deux côtés.
|
|
99
|
+
*/
|
|
100
|
+
export const financeConfigSchema = z.object({
|
|
101
|
+
currency: financeCurrencySchema,
|
|
102
|
+
vatEnabled: z.boolean()
|
|
103
|
+
});
|
|
104
|
+
export type FinanceConfig = z.infer<typeof financeConfigSchema>;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Nature d'un compte. Sert à deux choses seulement: l'icône de la carte, et le
|
|
108
|
+
* fait qu'une **épargne** soit comptée à part du disponible sur le tableau de
|
|
109
|
+
* bord (avoir 8 000 € dont 7 000 bloqués sur un livret n'est pas la même
|
|
110
|
+
* situation que 8 000 € sur un compte courant).
|
|
111
|
+
*/
|
|
112
|
+
export const financeAccountKindSchema = z.enum([
|
|
113
|
+
'checking',
|
|
114
|
+
'savings',
|
|
115
|
+
'cash',
|
|
116
|
+
'card',
|
|
117
|
+
'business',
|
|
118
|
+
'other'
|
|
119
|
+
]);
|
|
120
|
+
export type FinanceAccountKind = z.infer<typeof financeAccountKindSchema>;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Un compte, tel que le client le reçoit.
|
|
124
|
+
*
|
|
125
|
+
* Les trois soldes répondent à trois questions distinctes, et les confondre est
|
|
126
|
+
* la source d'erreur la plus courante d'un livre de comptes:
|
|
127
|
+
* - `balance`: ce qu'il y a aujourd'hui, opérations datées d'aujourd'hui ou
|
|
128
|
+
* d'avant comprises. C'est le solde, sans autre qualificatif.
|
|
129
|
+
* - `projected`: le même en tenant compte des opérations déjà saisies à une
|
|
130
|
+
* date future (un loyer prélevé le 5, saisi le 2).
|
|
131
|
+
* - `cleared`: seulement ce qui a été **pointé**, c'est-à-dire vu sur le relevé
|
|
132
|
+
* de la banque. C'est celui-là que l'on compare au relevé, et lui seul.
|
|
133
|
+
*/
|
|
134
|
+
export const financeAccountSchema = z.object({
|
|
135
|
+
id: z.number().int().positive(),
|
|
136
|
+
name: z.string().max(FINANCE_NAME_MAX_LENGTH),
|
|
137
|
+
kind: financeAccountKindSchema,
|
|
138
|
+
color: financeColorSchema,
|
|
139
|
+
/** Solde de départ, avant toute opération enregistrée dans DevEye. */
|
|
140
|
+
initialBalance: financeBalanceSchema,
|
|
141
|
+
balance: financeBalanceSchema,
|
|
142
|
+
projected: financeBalanceSchema,
|
|
143
|
+
cleared: financeBalanceSchema,
|
|
144
|
+
/** Nombre d'opérations rattachées, toutes dates confondues. */
|
|
145
|
+
transactionCount: z.number().int().nonnegative(),
|
|
146
|
+
/** Un compte archivé sort des totaux et des sélecteurs, sans rien perdre. */
|
|
147
|
+
archived: z.boolean(),
|
|
148
|
+
note: z.string().max(FINANCE_NOTE_MAX_LENGTH),
|
|
149
|
+
sortOrder: z.number().int().nonnegative(),
|
|
150
|
+
created: z.number().int().nonnegative()
|
|
151
|
+
});
|
|
152
|
+
export type FinanceAccount = z.infer<typeof financeAccountSchema>;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Sens d'une catégorie. Une catégorie ne sert qu'un sens: « Salaire » ne classe
|
|
156
|
+
* pas une dépense, et proposer les deux dans un seul sélecteur transforme le
|
|
157
|
+
* choix en fouille.
|
|
158
|
+
*/
|
|
159
|
+
export const financeFlowSchema = z.enum(['expense', 'income']);
|
|
160
|
+
export type FinanceFlow = z.infer<typeof financeFlowSchema>;
|
|
161
|
+
|
|
162
|
+
export const financeCategorySchema = z.object({
|
|
163
|
+
id: z.number().int().positive(),
|
|
164
|
+
name: z.string().max(FINANCE_NAME_MAX_LENGTH),
|
|
165
|
+
flow: financeFlowSchema,
|
|
166
|
+
color: financeColorSchema,
|
|
167
|
+
/** Classe d'icône (`icons.css`), sans le préfixe `icon-`. */
|
|
168
|
+
icon: z.string().max(40),
|
|
169
|
+
sortOrder: z.number().int().nonnegative()
|
|
170
|
+
});
|
|
171
|
+
export type FinanceCategory = z.infer<typeof financeCategorySchema>;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Nature d'une opération.
|
|
175
|
+
*
|
|
176
|
+
* Un **virement** est une seule ligne et non deux: il porte son compte de
|
|
177
|
+
* départ (`accountId`) et son compte d'arrivée (`transferAccountId`), et les
|
|
178
|
+
* deux soldes en tiennent compte. Le représenter par une paire de lignes
|
|
179
|
+
* obligerait à les garder cohérentes à chaque modification, et une paire à
|
|
180
|
+
* moitié supprimée ferait apparaître de l'argent.
|
|
181
|
+
*/
|
|
182
|
+
export const financeTransactionKindSchema = z.enum(['expense', 'income', 'transfer']);
|
|
183
|
+
export type FinanceTransactionKind = z.infer<typeof financeTransactionKindSchema>;
|
|
184
|
+
|
|
185
|
+
export const financeTransactionSchema = z.object({
|
|
186
|
+
id: z.number().int().positive(),
|
|
187
|
+
accountId: z.number().int().positive(),
|
|
188
|
+
kind: financeTransactionKindSchema,
|
|
189
|
+
amount: financeAmountSchema,
|
|
190
|
+
date: financeDateSchema,
|
|
191
|
+
label: z.string().max(FINANCE_LABEL_MAX_LENGTH),
|
|
192
|
+
categoryId: z.number().int().positive().nullable(),
|
|
193
|
+
/** Le compte crédité, pour un virement seulement. */
|
|
194
|
+
transferAccountId: z.number().int().positive().nullable(),
|
|
195
|
+
/** Qui a été payé, ou qui a payé. Texte libre, chiffré. */
|
|
196
|
+
counterparty: z.string().max(FINANCE_COUNTERPARTY_MAX_LENGTH),
|
|
197
|
+
note: z.string().max(FINANCE_NOTE_MAX_LENGTH),
|
|
198
|
+
/**
|
|
199
|
+
* Part de TVA du montant, en centimes, ou `null` quand la question ne se
|
|
200
|
+
* pose pas. Le **taux** n'est pas stocké: il se déduit, et le stocker
|
|
201
|
+
* ouvrirait la porte à un couple taux / montant incohérent, que rien ne
|
|
202
|
+
* pourrait ensuite départager.
|
|
203
|
+
*/
|
|
204
|
+
vatAmount: financeAmountSchema.nullable(),
|
|
205
|
+
/** Vue sur le relevé de la banque. C'est ce que compte `cleared`. */
|
|
206
|
+
cleared: z.boolean(),
|
|
207
|
+
/** L'échéance qui l'a engendrée, quand elle vient d'une échéance. */
|
|
208
|
+
recurringId: z.number().int().positive().nullable(),
|
|
209
|
+
created: z.number().int().nonnegative(),
|
|
210
|
+
updated: z.number().int().nonnegative()
|
|
211
|
+
});
|
|
212
|
+
export type FinanceTransaction = z.infer<typeof financeTransactionSchema>;
|
|
213
|
+
|
|
214
|
+
/** Périodicité d'un budget. */
|
|
215
|
+
export const financeBudgetPeriodSchema = z.enum(['monthly', 'quarterly', 'yearly']);
|
|
216
|
+
export type FinanceBudgetPeriod = z.infer<typeof financeBudgetPeriodSchema>;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Une enveloppe posée sur une catégorie.
|
|
220
|
+
*
|
|
221
|
+
* `spent` et `remaining` sont calculés pour la période **en cours** au moment de
|
|
222
|
+
* la lecture, jamais stockés: un budget est une règle, pas un compteur, et
|
|
223
|
+
* mémoriser le compteur le ferait diverger dès qu'une opération passée est
|
|
224
|
+
* corrigée.
|
|
225
|
+
*/
|
|
226
|
+
export const financeBudgetSchema = z.object({
|
|
227
|
+
id: z.number().int().positive(),
|
|
228
|
+
categoryId: z.number().int().positive(),
|
|
229
|
+
amount: financeAmountSchema,
|
|
230
|
+
period: financeBudgetPeriodSchema,
|
|
231
|
+
/** Consommé sur la période en cours. */
|
|
232
|
+
spent: financeAmountSchema,
|
|
233
|
+
/** Ce qu'il reste. Négatif quand l'enveloppe est dépassée. */
|
|
234
|
+
remaining: financeBalanceSchema,
|
|
235
|
+
/** Premier jour de la période en cours, pour situer le calcul. */
|
|
236
|
+
periodStart: financeDateSchema,
|
|
237
|
+
/** Premier jour de la période suivante (borne exclue). */
|
|
238
|
+
periodEnd: financeDateSchema
|
|
239
|
+
});
|
|
240
|
+
export type FinanceBudget = z.infer<typeof financeBudgetSchema>;
|
|
241
|
+
|
|
242
|
+
/** Cadence d'une échéance. Combinée à `interval`: « tous les 2 mois ». */
|
|
243
|
+
export const financeFrequencySchema = z.enum(['weekly', 'monthly', 'quarterly', 'yearly']);
|
|
244
|
+
export type FinanceFrequency = z.infer<typeof financeFrequencySchema>;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Une opération qui revient: loyer, salaire, abonnement, échéance de prêt.
|
|
248
|
+
*
|
|
249
|
+
* `automatic` décide de ce qui se passe quand la date arrive:
|
|
250
|
+
* - vrai: l'opération est écrite d'elle-même à la première lecture qui suit,
|
|
251
|
+
* parce qu'un salaire tombe qu'on regarde ou non;
|
|
252
|
+
* - faux: elle est proposée, et attend un clic. C'est ce qu'on veut d'une
|
|
253
|
+
* dépense dont le montant varie (électricité), qu'on ne veut pas voir
|
|
254
|
+
* apparaître à un montant faux.
|
|
255
|
+
*
|
|
256
|
+
* Voir `postDueRecurring` côté serveur pour le mécanisme, qui est une
|
|
257
|
+
* matérialisation paresseuse et non une tâche de fond.
|
|
258
|
+
*/
|
|
259
|
+
export const financeRecurringSchema = z.object({
|
|
260
|
+
id: z.number().int().positive(),
|
|
261
|
+
accountId: z.number().int().positive(),
|
|
262
|
+
kind: financeTransactionKindSchema,
|
|
263
|
+
amount: financeAmountSchema,
|
|
264
|
+
label: z.string().max(FINANCE_LABEL_MAX_LENGTH),
|
|
265
|
+
categoryId: z.number().int().positive().nullable(),
|
|
266
|
+
transferAccountId: z.number().int().positive().nullable(),
|
|
267
|
+
counterparty: z.string().max(FINANCE_COUNTERPARTY_MAX_LENGTH),
|
|
268
|
+
note: z.string().max(FINANCE_NOTE_MAX_LENGTH),
|
|
269
|
+
vatAmount: financeAmountSchema.nullable(),
|
|
270
|
+
frequency: financeFrequencySchema,
|
|
271
|
+
/** « Tous les N » de la cadence. 1 = à chaque fois. */
|
|
272
|
+
interval: z.number().int().positive().max(60),
|
|
273
|
+
/** Prochaine occurrence attendue. */
|
|
274
|
+
nextDate: financeDateSchema,
|
|
275
|
+
/** Dernier jour couvert, ou `null` pour sans fin. */
|
|
276
|
+
endDate: financeDateSchema.nullable(),
|
|
277
|
+
automatic: z.boolean(),
|
|
278
|
+
/** Suspendue: plus rien n'est écrit ni proposé, sans rien perdre. */
|
|
279
|
+
active: z.boolean(),
|
|
280
|
+
/** Date de la dernière occurrence effectivement écrite. */
|
|
281
|
+
lastPostedDate: financeDateSchema.nullable(),
|
|
282
|
+
created: z.number().int().nonnegative()
|
|
283
|
+
});
|
|
284
|
+
export type FinanceRecurring = z.infer<typeof financeRecurringSchema>;
|
|
285
|
+
|
|
286
|
+
/** Fenêtre d'analyse du tableau de bord. */
|
|
287
|
+
export const financeRangeSchema = z.enum(['month', 'quarter', 'year']);
|
|
288
|
+
export type FinanceRange = z.infer<typeof financeRangeSchema>;
|
|
289
|
+
|
|
290
|
+
/** Un mois de la frise entrées / sorties. */
|
|
291
|
+
export const financeMonthPointSchema = z.object({
|
|
292
|
+
month: financeMonthSchema,
|
|
293
|
+
income: financeAmountSchema,
|
|
294
|
+
expense: financeAmountSchema,
|
|
295
|
+
/** Solde cumulé de tous les comptes actifs à la fin de ce mois. */
|
|
296
|
+
balance: financeBalanceSchema
|
|
297
|
+
});
|
|
298
|
+
export type FinanceMonthPoint = z.infer<typeof financeMonthPointSchema>;
|
|
299
|
+
|
|
300
|
+
/** Une part de la répartition par catégorie sur la fenêtre. */
|
|
301
|
+
export const financeCategoryShareSchema = z.object({
|
|
302
|
+
/** `null` = les opérations sans catégorie, rassemblées. */
|
|
303
|
+
categoryId: z.number().int().positive().nullable(),
|
|
304
|
+
flow: financeFlowSchema,
|
|
305
|
+
amount: financeAmountSchema,
|
|
306
|
+
count: z.number().int().nonnegative()
|
|
307
|
+
});
|
|
308
|
+
export type FinanceCategoryShare = z.infer<typeof financeCategoryShareSchema>;
|
|
309
|
+
|
|
310
|
+
/** Une occurrence attendue, telle que l'annonce le tableau de bord. */
|
|
311
|
+
export const financeUpcomingSchema = z.object({
|
|
312
|
+
recurringId: z.number().int().positive(),
|
|
313
|
+
date: financeDateSchema,
|
|
314
|
+
label: z.string(),
|
|
315
|
+
kind: financeTransactionKindSchema,
|
|
316
|
+
amount: financeAmountSchema,
|
|
317
|
+
accountId: z.number().int().positive(),
|
|
318
|
+
categoryId: z.number().int().positive().nullable(),
|
|
319
|
+
automatic: z.boolean(),
|
|
320
|
+
/** L'échéance est en retard: sa date est déjà passée. */
|
|
321
|
+
overdue: z.boolean()
|
|
322
|
+
});
|
|
323
|
+
export type FinanceUpcoming = z.infer<typeof financeUpcomingSchema>;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Tout ce que montre le tableau de bord, en une réponse.
|
|
327
|
+
*
|
|
328
|
+
* Une seule commande et non six: ces chiffres se lisent ensemble et doivent
|
|
329
|
+
* être cohérents entre eux. Six allers-retours indépendants laisseraient un
|
|
330
|
+
* écran où le solde vient d'avant une écriture et la répartition d'après.
|
|
331
|
+
*/
|
|
332
|
+
export const financeOverviewSchema = z.object({
|
|
333
|
+
currency: financeCurrencySchema,
|
|
334
|
+
/** Bornes de la fenêtre analysée (`to` exclu). */
|
|
335
|
+
from: financeDateSchema,
|
|
336
|
+
to: financeDateSchema,
|
|
337
|
+
/** Somme des soldes du jour, comptes archivés exclus. */
|
|
338
|
+
netBalance: financeBalanceSchema,
|
|
339
|
+
/** La part de `netBalance` posée sur des comptes d'épargne. */
|
|
340
|
+
savings: financeBalanceSchema,
|
|
341
|
+
/** `netBalance` en tenant compte des opérations déjà datées plus tard. */
|
|
342
|
+
projected: financeBalanceSchema,
|
|
343
|
+
income: financeAmountSchema,
|
|
344
|
+
expense: financeAmountSchema,
|
|
345
|
+
/** Entrées moins sorties sur la fenêtre. Négatif quand on a puisé. */
|
|
346
|
+
net: financeBalanceSchema,
|
|
347
|
+
/** Même fenêtre, décalée d'une période en arrière, pour la comparaison. */
|
|
348
|
+
previousIncome: financeAmountSchema,
|
|
349
|
+
previousExpense: financeAmountSchema,
|
|
350
|
+
months: z.array(financeMonthPointSchema),
|
|
351
|
+
categories: z.array(financeCategoryShareSchema),
|
|
352
|
+
budgets: z.array(financeBudgetSchema),
|
|
353
|
+
upcoming: z.array(financeUpcomingSchema),
|
|
354
|
+
/** Récapitulatif TVA sur la fenêtre, ou `null` hors mode entreprise. */
|
|
355
|
+
vat: z
|
|
356
|
+
.object({
|
|
357
|
+
collected: financeAmountSchema,
|
|
358
|
+
deductible: financeAmountSchema,
|
|
359
|
+
/** Collectée moins déductible: ce qui est dû (positif) ou à récupérer. */
|
|
360
|
+
due: financeBalanceSchema
|
|
361
|
+
})
|
|
362
|
+
.nullable()
|
|
363
|
+
});
|
|
364
|
+
export type FinanceOverview = z.infer<typeof financeOverviewSchema>;
|
|
365
|
+
|
|
366
|
+
/** Ce que lit la carte de l'accueil. Volontairement minuscule. */
|
|
367
|
+
export const financeSummarySchema = z.object({
|
|
368
|
+
currency: financeCurrencySchema,
|
|
369
|
+
balance: financeBalanceSchema,
|
|
370
|
+
/** Entrées et sorties du mois civil en cours. */
|
|
371
|
+
income: financeAmountSchema,
|
|
372
|
+
expense: financeAmountSchema,
|
|
373
|
+
accountCount: z.number().int().nonnegative()
|
|
374
|
+
});
|
|
375
|
+
export type FinanceSummary = z.infer<typeof financeSummarySchema>;
|
|
376
|
+
|
|
377
|
+
/* ------------------------------------------------------------------ *
|
|
378
|
+
* Lignes SQL (serveur uniquement)
|
|
379
|
+
* ------------------------------------------------------------------ */
|
|
380
|
+
|
|
381
|
+
export interface FinanceConfigRow {
|
|
382
|
+
workspace_id: number;
|
|
383
|
+
currency: string;
|
|
384
|
+
vat_enabled: number;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export interface FinanceAccountRow {
|
|
388
|
+
id: number;
|
|
389
|
+
workspace_id: number;
|
|
390
|
+
kind: FinanceAccountKind;
|
|
391
|
+
color: FinanceColor;
|
|
392
|
+
initial_balance: number;
|
|
393
|
+
archived: number;
|
|
394
|
+
sort_order: number;
|
|
395
|
+
/** `{ name, note }` chiffré, étage ouvert. */
|
|
396
|
+
content: string;
|
|
397
|
+
created: number;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** Une ligne de compte accompagnée de ses soldes calculés par la requête. */
|
|
401
|
+
export interface FinanceAccountBalanceRow extends FinanceAccountRow {
|
|
402
|
+
balance: number;
|
|
403
|
+
projected: number;
|
|
404
|
+
cleared: number;
|
|
405
|
+
transaction_count: number;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export interface FinanceCategoryRow {
|
|
409
|
+
id: number;
|
|
410
|
+
workspace_id: number;
|
|
411
|
+
flow: FinanceFlow;
|
|
412
|
+
color: FinanceColor;
|
|
413
|
+
icon: string;
|
|
414
|
+
sort_order: number;
|
|
415
|
+
/** `{ name }` chiffré, étage ouvert. */
|
|
416
|
+
content: string;
|
|
417
|
+
created: number;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export interface FinanceTransactionRow {
|
|
421
|
+
id: number;
|
|
422
|
+
workspace_id: number;
|
|
423
|
+
account_id: number;
|
|
424
|
+
transfer_account_id: number | null;
|
|
425
|
+
category_id: number | null;
|
|
426
|
+
recurring_id: number | null;
|
|
427
|
+
kind: FinanceTransactionKind;
|
|
428
|
+
amount: number;
|
|
429
|
+
vat_amount: number | null;
|
|
430
|
+
/**
|
|
431
|
+
* `AAAA-MM-JJ`. La colonne est un vrai `DATE`, dont le pilote rendrait un
|
|
432
|
+
* objet `Date`: le dépôt la projette systématiquement par `DATE_FORMAT`,
|
|
433
|
+
* pour qu'aucun fuseau ne s'interpose entre la base et l'écran.
|
|
434
|
+
*/
|
|
435
|
+
date: string;
|
|
436
|
+
cleared: number;
|
|
437
|
+
/** `{ label, counterparty, note }` chiffré, étage ouvert. */
|
|
438
|
+
content: string;
|
|
439
|
+
created: number;
|
|
440
|
+
updated: number;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export interface FinanceBudgetRow {
|
|
444
|
+
id: number;
|
|
445
|
+
workspace_id: number;
|
|
446
|
+
category_id: number;
|
|
447
|
+
amount: number;
|
|
448
|
+
period: FinanceBudgetPeriod;
|
|
449
|
+
created: number;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export interface FinanceRecurringRow {
|
|
453
|
+
id: number;
|
|
454
|
+
workspace_id: number;
|
|
455
|
+
account_id: number;
|
|
456
|
+
transfer_account_id: number | null;
|
|
457
|
+
category_id: number | null;
|
|
458
|
+
kind: FinanceTransactionKind;
|
|
459
|
+
amount: number;
|
|
460
|
+
vat_amount: number | null;
|
|
461
|
+
frequency: FinanceFrequency;
|
|
462
|
+
interval_count: number;
|
|
463
|
+
next_date: string;
|
|
464
|
+
/**
|
|
465
|
+
* Jour du mois de la série (1 à 31), `null` pour une cadence hebdomadaire.
|
|
466
|
+
* Dérivé de `next_date` à l'écriture, jamais fourni par le client: c'est ce
|
|
467
|
+
* qui empêche une échéance au 31 de dériver au 28 après un février.
|
|
468
|
+
*/
|
|
469
|
+
anchor_day: number | null;
|
|
470
|
+
end_date: string | null;
|
|
471
|
+
last_posted_date: string | null;
|
|
472
|
+
automatic: number;
|
|
473
|
+
active: number;
|
|
474
|
+
/** `{ label, counterparty, note }` chiffré, étage ouvert. */
|
|
475
|
+
content: string;
|
|
476
|
+
created: number;
|
|
477
|
+
}
|