@hed-hog/finance 0.0.257 → 0.0.261

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.
Files changed (64) hide show
  1. package/dist/dto/create-bank-statement-adjustment.dto.d.ts +8 -0
  2. package/dist/dto/create-bank-statement-adjustment.dto.d.ts.map +1 -0
  3. package/dist/dto/create-bank-statement-adjustment.dto.js +50 -0
  4. package/dist/dto/create-bank-statement-adjustment.dto.js.map +1 -0
  5. package/dist/dto/create-transfer.dto.d.ts +8 -0
  6. package/dist/dto/create-transfer.dto.d.ts.map +1 -0
  7. package/dist/dto/create-transfer.dto.js +52 -0
  8. package/dist/dto/create-transfer.dto.js.map +1 -0
  9. package/dist/dto/register-collection-agreement.dto.d.ts +7 -0
  10. package/dist/dto/register-collection-agreement.dto.d.ts.map +1 -0
  11. package/dist/dto/register-collection-agreement.dto.js +37 -0
  12. package/dist/dto/register-collection-agreement.dto.js.map +1 -0
  13. package/dist/dto/send-collection.dto.d.ts +5 -0
  14. package/dist/dto/send-collection.dto.d.ts.map +1 -0
  15. package/dist/dto/send-collection.dto.js +29 -0
  16. package/dist/dto/send-collection.dto.js.map +1 -0
  17. package/dist/dto/settle-installment.dto.d.ts +1 -0
  18. package/dist/dto/settle-installment.dto.d.ts.map +1 -1
  19. package/dist/dto/settle-installment.dto.js +6 -0
  20. package/dist/dto/settle-installment.dto.js.map +1 -1
  21. package/dist/finance-collections.controller.d.ts +35 -0
  22. package/dist/finance-collections.controller.d.ts.map +1 -0
  23. package/dist/finance-collections.controller.js +65 -0
  24. package/dist/finance-collections.controller.js.map +1 -0
  25. package/dist/finance-data.controller.d.ts +4 -0
  26. package/dist/finance-data.controller.d.ts.map +1 -1
  27. package/dist/finance-installments.controller.d.ts +44 -0
  28. package/dist/finance-installments.controller.d.ts.map +1 -1
  29. package/dist/finance-statements.controller.d.ts +16 -2
  30. package/dist/finance-statements.controller.d.ts.map +1 -1
  31. package/dist/finance-statements.controller.js +34 -6
  32. package/dist/finance-statements.controller.js.map +1 -1
  33. package/dist/finance-transfers.controller.d.ts +23 -0
  34. package/dist/finance-transfers.controller.d.ts.map +1 -0
  35. package/dist/finance-transfers.controller.js +56 -0
  36. package/dist/finance-transfers.controller.js.map +1 -0
  37. package/dist/finance.module.d.ts.map +1 -1
  38. package/dist/finance.module.js +4 -0
  39. package/dist/finance.module.js.map +1 -1
  40. package/dist/finance.service.d.ts +115 -2
  41. package/dist/finance.service.d.ts.map +1 -1
  42. package/dist/finance.service.js +632 -8
  43. package/dist/finance.service.js.map +1 -1
  44. package/dist/index.d.ts +2 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +2 -0
  47. package/dist/index.js.map +1 -1
  48. package/hedhog/data/route.yaml +63 -0
  49. package/hedhog/frontend/app/accounts-receivable/collections-default/page.tsx.ejs +643 -440
  50. package/hedhog/frontend/app/cash-and-banks/bank-reconciliation/page.tsx.ejs +825 -477
  51. package/hedhog/frontend/app/cash-and-banks/statements/page.tsx.ejs +367 -43
  52. package/hedhog/frontend/app/cash-and-banks/transfers/page.tsx.ejs +315 -75
  53. package/package.json +4 -4
  54. package/src/dto/create-bank-statement-adjustment.dto.ts +38 -0
  55. package/src/dto/create-transfer.dto.ts +46 -0
  56. package/src/dto/register-collection-agreement.dto.ts +27 -0
  57. package/src/dto/send-collection.dto.ts +14 -0
  58. package/src/dto/settle-installment.dto.ts +5 -0
  59. package/src/finance-collections.controller.ts +34 -0
  60. package/src/finance-statements.controller.ts +29 -1
  61. package/src/finance-transfers.controller.ts +26 -0
  62. package/src/finance.module.ts +4 -0
  63. package/src/finance.service.ts +775 -5
  64. package/src/index.ts +2 -0
@@ -9,9 +9,17 @@ import {
9
9
  CardHeader,
10
10
  CardTitle,
11
11
  } from '@/components/ui/card';
12
+ import { FilterBar } from '@/components/ui/filter-bar';
13
+ import {
14
+ Form,
15
+ FormControl,
16
+ FormField,
17
+ FormItem,
18
+ FormLabel,
19
+ FormMessage,
20
+ } from '@/components/ui/form';
12
21
  import { Input } from '@/components/ui/input';
13
22
  import { InputMoney } from '@/components/ui/input-money';
14
- import { Label } from '@/components/ui/label';
15
23
  import { Money } from '@/components/ui/money';
16
24
  import {
17
25
  Select,
@@ -26,7 +34,6 @@ import {
26
34
  SheetDescription,
27
35
  SheetHeader,
28
36
  SheetTitle,
29
- SheetTrigger,
30
37
  } from '@/components/ui/sheet';
31
38
  import {
32
39
  Table,
@@ -37,93 +44,244 @@ import {
37
44
  TableRow,
38
45
  } from '@/components/ui/table';
39
46
  import { Textarea } from '@/components/ui/textarea';
47
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
48
+ import { zodResolver } from '@hookform/resolvers/zod';
40
49
  import { ArrowRight, Plus } from 'lucide-react';
41
50
  import { useTranslations } from 'next-intl';
51
+ import { useEffect, useState } from 'react';
52
+ import { useForm } from 'react-hook-form';
53
+ import { z } from 'zod';
42
54
  import { formatarData } from '../../_lib/formatters';
43
- import { useFinanceData } from '../../_lib/use-finance-data';
55
+
56
+ type BankAccount = {
57
+ id: string;
58
+ banco: string;
59
+ descricao: string;
60
+ ativo: boolean;
61
+ };
62
+
63
+ type Transfer = {
64
+ id: string;
65
+ contaOrigemId: string;
66
+ contaDestinoId: string;
67
+ data: string;
68
+ valor: number;
69
+ descricao: string;
70
+ };
71
+
72
+ const transferFormSchema = z
73
+ .object({
74
+ sourceAccountId: z.string().trim().min(1, 'Conta de origem é obrigatória'),
75
+ destinationAccountId: z
76
+ .string()
77
+ .trim()
78
+ .min(1, 'Conta de destino é obrigatória'),
79
+ date: z.string().trim().min(1, 'Data é obrigatória'),
80
+ amount: z.number().min(0.01, 'Valor deve ser maior que zero'),
81
+ description: z.string().optional(),
82
+ })
83
+ .refine((values) => values.sourceAccountId !== values.destinationAccountId, {
84
+ message: 'As contas de origem e destino devem ser diferentes',
85
+ path: ['destinationAccountId'],
86
+ });
87
+
88
+ type TransferFormValues = z.infer<typeof transferFormSchema>;
44
89
 
45
90
  function NovaTransferenciaSheet({
46
91
  contasBancarias,
47
92
  t,
93
+ onCreated,
48
94
  }: {
49
- contasBancarias: any[];
95
+ contasBancarias: BankAccount[];
50
96
  t: ReturnType<typeof useTranslations>;
97
+ onCreated: () => Promise<void> | void;
51
98
  }) {
99
+ const { request, showToastHandler } = useApp();
100
+ const [open, setOpen] = useState(false);
101
+
102
+ const form = useForm<TransferFormValues>({
103
+ resolver: zodResolver(transferFormSchema),
104
+ defaultValues: {
105
+ sourceAccountId: '',
106
+ destinationAccountId: '',
107
+ date: new Date().toISOString().slice(0, 10),
108
+ amount: 0,
109
+ description: '',
110
+ },
111
+ });
112
+
113
+ useEffect(() => {
114
+ if (!open) {
115
+ return;
116
+ }
117
+
118
+ form.reset({
119
+ sourceAccountId: '',
120
+ destinationAccountId: '',
121
+ date: new Date().toISOString().slice(0, 10),
122
+ amount: 0,
123
+ description: '',
124
+ });
125
+ }, [form, open]);
126
+
127
+ const handleSubmit = async (values: TransferFormValues) => {
128
+ try {
129
+ await request({
130
+ url: '/finance/transfers',
131
+ method: 'POST',
132
+ data: {
133
+ source_account_id: Number(values.sourceAccountId),
134
+ destination_account_id: Number(values.destinationAccountId),
135
+ date: values.date,
136
+ amount: values.amount,
137
+ description: values.description?.trim() || undefined,
138
+ },
139
+ });
140
+
141
+ await onCreated();
142
+ setOpen(false);
143
+ showToastHandler?.('success', 'Transferência cadastrada com sucesso');
144
+ } catch {
145
+ showToastHandler?.('error', 'Erro ao cadastrar transferência');
146
+ }
147
+ };
148
+
52
149
  return (
53
- <Sheet>
54
- <SheetTrigger asChild>
55
- <Button>
56
- <Plus className="mr-2 h-4 w-4" />
57
- {t('newTransfer.action')}
58
- </Button>
59
- </SheetTrigger>
60
- <SheetContent className="w-full sm:max-w-lg">
150
+ <Sheet open={open} onOpenChange={setOpen}>
151
+ <Button onClick={() => setOpen(true)}>
152
+ <Plus className="mr-2 h-4 w-4" />
153
+ {t('newTransfer.action')}
154
+ </Button>
155
+ <SheetContent className="w-full sm:max-w-lg overflow-y-auto">
61
156
  <SheetHeader>
62
157
  <SheetTitle>{t('newTransfer.title')}</SheetTitle>
63
158
  <SheetDescription>{t('newTransfer.description')}</SheetDescription>
64
159
  </SheetHeader>
65
- <form
66
- className="mt-6 space-y-4"
67
- onSubmit={(event) => event.preventDefault()}
68
- >
69
- <div className="grid gap-4">
70
- <div className="space-y-2">
71
- <Label htmlFor="contaOrigem">{t('fields.sourceAccount')}</Label>
72
- <Select>
73
- <SelectTrigger>
74
- <SelectValue placeholder={t('common.select')} />
75
- </SelectTrigger>
76
- <SelectContent>
77
- {contasBancarias.map((conta) => (
78
- <SelectItem key={conta.id} value={conta.id}>
79
- {conta.banco} - {conta.descricao}
80
- </SelectItem>
81
- ))}
82
- </SelectContent>
83
- </Select>
84
- </div>
85
- <div className="space-y-2">
86
- <Label htmlFor="contaDestino">
87
- {t('fields.destinationAccount')}
88
- </Label>
89
- <Select>
90
- <SelectTrigger>
91
- <SelectValue placeholder={t('common.select')} />
92
- </SelectTrigger>
93
- <SelectContent>
94
- {contasBancarias.map((conta) => (
95
- <SelectItem key={conta.id} value={conta.id}>
96
- {conta.banco} - {conta.descricao}
97
- </SelectItem>
98
- ))}
99
- </SelectContent>
100
- </Select>
101
- </div>
160
+
161
+ <Form {...form}>
162
+ <form
163
+ className="space-y-4 px-4"
164
+ onSubmit={form.handleSubmit(handleSubmit)}
165
+ >
166
+ <FormField
167
+ control={form.control}
168
+ name="sourceAccountId"
169
+ render={({ field }) => (
170
+ <FormItem>
171
+ <FormLabel>{t('fields.sourceAccount')}</FormLabel>
172
+ <Select value={field.value} onValueChange={field.onChange}>
173
+ <FormControl>
174
+ <SelectTrigger>
175
+ <SelectValue placeholder={t('common.select')} />
176
+ </SelectTrigger>
177
+ </FormControl>
178
+ <SelectContent>
179
+ {contasBancarias.map((conta) => (
180
+ <SelectItem key={conta.id} value={conta.id}>
181
+ {conta.banco} - {conta.descricao}
182
+ </SelectItem>
183
+ ))}
184
+ </SelectContent>
185
+ </Select>
186
+ <FormMessage />
187
+ </FormItem>
188
+ )}
189
+ />
190
+
191
+ <FormField
192
+ control={form.control}
193
+ name="destinationAccountId"
194
+ render={({ field }) => (
195
+ <FormItem>
196
+ <FormLabel>{t('fields.destinationAccount')}</FormLabel>
197
+ <Select value={field.value} onValueChange={field.onChange}>
198
+ <FormControl>
199
+ <SelectTrigger>
200
+ <SelectValue placeholder={t('common.select')} />
201
+ </SelectTrigger>
202
+ </FormControl>
203
+ <SelectContent>
204
+ {contasBancarias.map((conta) => (
205
+ <SelectItem key={conta.id} value={conta.id}>
206
+ {conta.banco} - {conta.descricao}
207
+ </SelectItem>
208
+ ))}
209
+ </SelectContent>
210
+ </Select>
211
+ <FormMessage />
212
+ </FormItem>
213
+ )}
214
+ />
215
+
102
216
  <div className="grid grid-cols-2 gap-4">
103
- <div className="space-y-2">
104
- <Label htmlFor="data">{t('fields.date')}</Label>
105
- <Input id="data" type="date" />
106
- </div>
107
- <div className="space-y-2">
108
- <Label htmlFor="valor">{t('fields.value')}</Label>
109
- <InputMoney id="valor" placeholder="0,00" />
110
- </div>
111
- </div>
112
- <div className="space-y-2">
113
- <Label htmlFor="descricao">{t('fields.description')}</Label>
114
- <Textarea
115
- id="descricao"
116
- placeholder={t('fields.descriptionPlaceholder')}
217
+ <FormField
218
+ control={form.control}
219
+ name="date"
220
+ render={({ field }) => (
221
+ <FormItem>
222
+ <FormLabel>{t('fields.date')}</FormLabel>
223
+ <FormControl>
224
+ <Input type="date" {...field} />
225
+ </FormControl>
226
+ <FormMessage />
227
+ </FormItem>
228
+ )}
229
+ />
230
+
231
+ <FormField
232
+ control={form.control}
233
+ name="amount"
234
+ render={({ field }) => (
235
+ <FormItem>
236
+ <FormLabel>{t('fields.value')}</FormLabel>
237
+ <FormControl>
238
+ <InputMoney
239
+ ref={field.ref}
240
+ name={field.name}
241
+ value={field.value}
242
+ onBlur={field.onBlur}
243
+ onValueChange={(value) => field.onChange(value ?? 0)}
244
+ placeholder="0,00"
245
+ />
246
+ </FormControl>
247
+ <FormMessage />
248
+ </FormItem>
249
+ )}
117
250
  />
118
251
  </div>
119
- </div>
120
- <div className="flex justify-end gap-2 pt-4">
121
- <Button type="button" variant="outline">
122
- {t('common.cancel')}
123
- </Button>
124
- <Button type="submit">{t('newTransfer.submit')}</Button>
125
- </div>
126
- </form>
252
+
253
+ <FormField
254
+ control={form.control}
255
+ name="description"
256
+ render={({ field }) => (
257
+ <FormItem>
258
+ <FormLabel>{t('fields.description')}</FormLabel>
259
+ <FormControl>
260
+ <Textarea
261
+ placeholder={t('fields.descriptionPlaceholder')}
262
+ {...field}
263
+ value={field.value || ''}
264
+ />
265
+ </FormControl>
266
+ <FormMessage />
267
+ </FormItem>
268
+ )}
269
+ />
270
+
271
+ <div className="flex justify-end gap-2 pt-4">
272
+ <Button
273
+ type="button"
274
+ variant="outline"
275
+ onClick={() => setOpen(false)}
276
+ >
277
+ {t('common.cancel')}
278
+ </Button>
279
+ <Button type="submit" disabled={form.formState.isSubmitting}>
280
+ {t('newTransfer.submit')}
281
+ </Button>
282
+ </div>
283
+ </form>
284
+ </Form>
127
285
  </SheetContent>
128
286
  </Sheet>
129
287
  );
@@ -131,8 +289,62 @@ function NovaTransferenciaSheet({
131
289
 
132
290
  export default function TransferenciasPage() {
133
291
  const t = useTranslations('finance.TransfersPage');
134
- const { data } = useFinanceData();
135
- const { transferencias, contasBancarias } = data;
292
+ const { request } = useApp();
293
+ const [search, setSearch] = useState('');
294
+ const [debouncedSearch, setDebouncedSearch] = useState('');
295
+ const [accountFilter, setAccountFilter] = useState('all');
296
+
297
+ useEffect(() => {
298
+ const timeoutId = window.setTimeout(() => {
299
+ setDebouncedSearch(search);
300
+ }, 300);
301
+
302
+ return () => {
303
+ window.clearTimeout(timeoutId);
304
+ };
305
+ }, [search]);
306
+
307
+ const { data: contasBancarias = [], refetch: refetchContasBancarias } =
308
+ useQuery<BankAccount[]>({
309
+ queryKey: ['finance-bank-accounts'],
310
+ queryFn: async () => {
311
+ const response = await request({
312
+ url: '/finance/bank-accounts',
313
+ method: 'GET',
314
+ });
315
+
316
+ return (response?.data || []) as BankAccount[];
317
+ },
318
+ });
319
+
320
+ const { data: transferencias = [], refetch: refetchTransferencias } =
321
+ useQuery<Transfer[]>({
322
+ queryKey: ['finance-transfers', debouncedSearch, accountFilter],
323
+ queryFn: async () => {
324
+ const params = new URLSearchParams();
325
+
326
+ const trimmedSearch = debouncedSearch.trim();
327
+ if (trimmedSearch) {
328
+ params.set('search', trimmedSearch);
329
+ }
330
+
331
+ if (accountFilter !== 'all') {
332
+ params.set('bank_account_id', accountFilter);
333
+ }
334
+
335
+ const query = params.toString();
336
+ const response = await request({
337
+ url: query ? `/finance/transfers?${query}` : '/finance/transfers',
338
+ method: 'GET',
339
+ });
340
+
341
+ return (response?.data || []) as Transfer[];
342
+ },
343
+ });
344
+
345
+ const handleTransferCreated = async () => {
346
+ await Promise.all([refetchTransferencias(), refetchContasBancarias()]);
347
+ };
136
348
 
137
349
  const totalTransferido = transferencias.reduce((acc, t) => acc + t.valor, 0);
138
350
 
@@ -147,10 +359,38 @@ export default function TransferenciasPage() {
147
359
  { label: t('breadcrumbs.current') },
148
360
  ]}
149
361
  actions={
150
- <NovaTransferenciaSheet contasBancarias={contasBancarias} t={t} />
362
+ <NovaTransferenciaSheet
363
+ contasBancarias={contasBancarias}
364
+ t={t}
365
+ onCreated={handleTransferCreated}
366
+ />
151
367
  }
152
368
  />
153
369
 
370
+ <div className="flex flex-col gap-4 sm:flex-row sm:items-center">
371
+ <Select value={accountFilter} onValueChange={setAccountFilter}>
372
+ <SelectTrigger className="w-full sm:w-[280px]">
373
+ <SelectValue placeholder={t('common.select')} />
374
+ </SelectTrigger>
375
+ <SelectContent>
376
+ <SelectItem value="all">Todas as contas</SelectItem>
377
+ {contasBancarias.map((conta) => (
378
+ <SelectItem key={conta.id} value={conta.id}>
379
+ {conta.banco} - {conta.descricao}
380
+ </SelectItem>
381
+ ))}
382
+ </SelectContent>
383
+ </Select>
384
+
385
+ <div className="flex-1">
386
+ <FilterBar
387
+ searchPlaceholder="Buscar na descrição..."
388
+ searchValue={search}
389
+ onSearchChange={setSearch}
390
+ />
391
+ </div>
392
+ </div>
393
+
154
394
  <div className="grid gap-4 md:grid-cols-2">
155
395
  <Card>
156
396
  <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
@@ -175,7 +415,7 @@ export default function TransferenciasPage() {
175
415
  </CardHeader>
176
416
  <CardContent>
177
417
  <div className="text-2xl font-bold">
178
- {contasBancarias.filter((c) => c.ativo).length}
418
+ {contasBancarias.filter((conta) => conta.ativo).length}
179
419
  </div>
180
420
  <p className="text-xs text-muted-foreground">
181
421
  {t('cards.available')}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/finance",
3
- "version": "0.0.257",
3
+ "version": "0.0.261",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -10,13 +10,13 @@
10
10
  "@nestjs/jwt": "^11",
11
11
  "@nestjs/mapped-types": "*",
12
12
  "@hed-hog/api-pagination": "0.0.5",
13
- "@hed-hog/contact": "0.0.257",
13
+ "@hed-hog/contact": "0.0.261",
14
14
  "@hed-hog/api-prisma": "0.0.4",
15
- "@hed-hog/tag": "0.0.257",
16
15
  "@hed-hog/api-locale": "0.0.11",
17
16
  "@hed-hog/api-types": "0.0.1",
17
+ "@hed-hog/tag": "0.0.261",
18
18
  "@hed-hog/api": "0.0.3",
19
- "@hed-hog/core": "0.0.257"
19
+ "@hed-hog/core": "0.0.261"
20
20
  },
21
21
  "exports": {
22
22
  ".": {
@@ -0,0 +1,38 @@
1
+ import { getLocaleText } from '@hed-hog/api-locale';
2
+ import { Type } from 'class-transformer';
3
+ import { IsDateString, IsNumber, IsOptional, IsString, Min } from 'class-validator';
4
+
5
+ export class CreateBankStatementAdjustmentDto {
6
+ @Type(() => Number)
7
+ @IsNumber(
8
+ {},
9
+ {
10
+ message: (args) =>
11
+ getLocaleText('validation.bankAccountIdMustBeNumber', args.value),
12
+ },
13
+ )
14
+ bank_account_id: number;
15
+
16
+ @Type(() => Number)
17
+ @IsNumber(
18
+ {},
19
+ {
20
+ message: (args) => getLocaleText('validation.amountMustBeNumber', args.value),
21
+ },
22
+ )
23
+ @Min(0.01, {
24
+ message: (args) => getLocaleText('validation.amountMustBeNumber', args.value),
25
+ })
26
+ amount: number;
27
+
28
+ @IsOptional()
29
+ @IsDateString()
30
+ date?: string;
31
+
32
+ @IsString()
33
+ type: string;
34
+
35
+ @IsOptional()
36
+ @IsString()
37
+ description?: string;
38
+ }
@@ -0,0 +1,46 @@
1
+ import { getLocaleText } from '@hed-hog/api-locale';
2
+ import { IsNumber, IsOptional, IsString, Min } from 'class-validator';
3
+
4
+ export class CreateTransferDto {
5
+ @IsNumber(
6
+ {},
7
+ {
8
+ message: (args) =>
9
+ getLocaleText('validation.bankAccountIdMustBeNumber', args.value),
10
+ },
11
+ )
12
+ source_account_id: number;
13
+
14
+ @IsNumber(
15
+ {},
16
+ {
17
+ message: (args) =>
18
+ getLocaleText('validation.bankAccountIdMustBeNumber', args.value),
19
+ },
20
+ )
21
+ destination_account_id: number;
22
+
23
+ @IsString({
24
+ message: (args) => getLocaleText('validation.dateMustBeString', args.value),
25
+ })
26
+ date: string;
27
+
28
+ @IsNumber(
29
+ {},
30
+ {
31
+ message: (args) =>
32
+ getLocaleText('validation.amountMustBeNumber', args.value),
33
+ },
34
+ )
35
+ @Min(0.01, {
36
+ message: (args) => getLocaleText('validation.amountMustBeNumber', args.value),
37
+ })
38
+ amount: number;
39
+
40
+ @IsOptional()
41
+ @IsString({
42
+ message: (args) =>
43
+ getLocaleText('validation.descriptionMustBeString', args.value),
44
+ })
45
+ description?: string;
46
+ }
@@ -0,0 +1,27 @@
1
+ import {
2
+ IsDateString,
3
+ IsInt,
4
+ IsNumber,
5
+ IsOptional,
6
+ IsString,
7
+ Max,
8
+ Min,
9
+ } from 'class-validator';
10
+
11
+ export class RegisterCollectionAgreementDto {
12
+ @IsNumber({ maxDecimalPlaces: 2 })
13
+ @Min(0.01)
14
+ amount: number;
15
+
16
+ @IsInt()
17
+ @Min(1)
18
+ @Max(120)
19
+ installments: number;
20
+
21
+ @IsDateString()
22
+ first_due_date: string;
23
+
24
+ @IsOptional()
25
+ @IsString()
26
+ notes?: string;
27
+ }
@@ -0,0 +1,14 @@
1
+ import { IsOptional, IsString, MaxLength, MinLength } from 'class-validator';
2
+
3
+ export class SendCollectionDto {
4
+
5
+ @IsString()
6
+ @MinLength(5)
7
+ @MaxLength(2000)
8
+ message: string;
9
+
10
+ @IsOptional()
11
+ @IsString()
12
+ @MaxLength(255)
13
+ subject?: string;
14
+ }
@@ -27,6 +27,11 @@ export class SettleInstallmentDto {
27
27
  @IsInt()
28
28
  bank_account_id?: number;
29
29
 
30
+ @IsOptional()
31
+ @Type(() => Number)
32
+ @IsInt()
33
+ bank_statement_line_id?: number;
34
+
30
35
  @IsOptional()
31
36
  @IsString()
32
37
  payment_channel?: string;
@@ -0,0 +1,34 @@
1
+ import { Role, User } from '@hed-hog/api';
2
+ import { Body, Controller, Get, Param, ParseIntPipe, Post } from '@nestjs/common';
3
+ import { RegisterCollectionAgreementDto } from './dto/register-collection-agreement.dto';
4
+ import { SendCollectionDto } from './dto/send-collection.dto';
5
+ import { FinanceService } from './finance.service';
6
+
7
+ @Role()
8
+ @Controller('finance')
9
+ export class FinanceCollectionsController {
10
+ constructor(private readonly financeService: FinanceService) {}
11
+
12
+ @Get('accounts-receivable/collections-default')
13
+ async getAccountsReceivableCollectionsDefault() {
14
+ return this.financeService.getAccountsReceivableCollectionsDefault();
15
+ }
16
+
17
+ @Post('accounts-receivable/collections-default/:personId/send')
18
+ async sendCollection(
19
+ @Param('personId', ParseIntPipe) personId: number,
20
+ @Body() data: SendCollectionDto,
21
+ @User() user,
22
+ ) {
23
+ return this.financeService.sendCollection(personId, data, user?.id);
24
+ }
25
+
26
+ @Post('accounts-receivable/collections-default/:personId/agreements')
27
+ async registerCollectionAgreement(
28
+ @Param('personId', ParseIntPipe) personId: number,
29
+ @Body() data: RegisterCollectionAgreementDto,
30
+ @User() user,
31
+ ) {
32
+ return this.financeService.registerCollectionAgreement(personId, data, user?.id);
33
+ }
34
+ }