@hed-hog/finance 0.0.231 → 0.0.233
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/dist/dto/create-financial-title.dto.d.ts +1 -0
- package/dist/dto/create-financial-title.dto.d.ts.map +1 -1
- package/dist/dto/create-financial-title.dto.js +11 -0
- package/dist/dto/create-financial-title.dto.js.map +1 -1
- package/dist/dto/extract-financial-title-from-file.dto.d.ts +4 -0
- package/dist/dto/extract-financial-title-from-file.dto.d.ts.map +1 -0
- package/dist/dto/extract-financial-title-from-file.dto.js +24 -0
- package/dist/dto/extract-financial-title-from-file.dto.js.map +1 -0
- package/dist/finance-installments.controller.d.ts +39 -0
- package/dist/finance-installments.controller.d.ts.map +1 -1
- package/dist/finance-installments.controller.js +26 -0
- package/dist/finance-installments.controller.js.map +1 -1
- package/dist/finance.module.d.ts.map +1 -1
- package/dist/finance.module.js +3 -1
- package/dist/finance.module.js.map +1 -1
- package/dist/finance.service.d.ts +33 -1
- package/dist/finance.service.d.ts.map +1 -1
- package/dist/finance.service.js +213 -2
- package/dist/finance.service.js.map +1 -1
- package/hedhog/data/route.yaml +18 -0
- package/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +234 -4
- package/hedhog/frontend/app/accounts-receivable/installments/page.tsx.ejs +205 -0
- package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +78 -61
- package/package.json +6 -5
- package/src/dto/create-financial-title.dto.ts +12 -0
- package/src/dto/extract-financial-title-from-file.dto.ts +9 -0
- package/src/finance-installments.controller.ts +33 -7
- package/src/finance.module.ts +3 -1
- package/src/finance.service.ts +251 -3
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import { Input } from '@/components/ui/input';
|
|
23
23
|
import { InputMoney } from '@/components/ui/input-money';
|
|
24
24
|
import { Money } from '@/components/ui/money';
|
|
25
|
+
import { Progress } from '@/components/ui/progress';
|
|
25
26
|
import {
|
|
26
27
|
Select,
|
|
27
28
|
SelectContent,
|
|
@@ -95,6 +96,29 @@ function NovoTituloSheet({
|
|
|
95
96
|
}) {
|
|
96
97
|
const { request, showToastHandler } = useApp();
|
|
97
98
|
const [open, setOpen] = useState(false);
|
|
99
|
+
const [uploadedFileId, setUploadedFileId] = useState<number | null>(null);
|
|
100
|
+
const [uploadedFileName, setUploadedFileName] = useState('');
|
|
101
|
+
const [isUploadingFile, setIsUploadingFile] = useState(false);
|
|
102
|
+
const [isExtractingFileData, setIsExtractingFileData] = useState(false);
|
|
103
|
+
const [uploadProgress, setUploadProgress] = useState(0);
|
|
104
|
+
|
|
105
|
+
const normalizeFilenameForDisplay = (filename: string) => {
|
|
106
|
+
if (!filename) {
|
|
107
|
+
return filename;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!/Ã.|Â.|â[\u0080-\u00BF]/.test(filename)) {
|
|
111
|
+
return filename;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const bytes = Uint8Array.from(filename, (char) => char.charCodeAt(0));
|
|
116
|
+
const decoded = new TextDecoder('utf-8').decode(bytes);
|
|
117
|
+
return /Ã.|Â.|â[\u0080-\u00BF]/.test(decoded) ? filename : decoded;
|
|
118
|
+
} catch {
|
|
119
|
+
return filename;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
98
122
|
|
|
99
123
|
const form = useForm<NewTitleFormValues>({
|
|
100
124
|
resolver: zodResolver(newTitleFormSchema),
|
|
@@ -132,11 +156,14 @@ function NovoTituloSheet({
|
|
|
132
156
|
: undefined,
|
|
133
157
|
payment_channel: values.canal || undefined,
|
|
134
158
|
description: values.descricao?.trim() || undefined,
|
|
159
|
+
attachment_file_ids: uploadedFileId ? [uploadedFileId] : undefined,
|
|
135
160
|
},
|
|
136
161
|
});
|
|
137
162
|
|
|
138
163
|
await onCreated();
|
|
139
164
|
form.reset();
|
|
165
|
+
setUploadedFileId(null);
|
|
166
|
+
setUploadedFileName('');
|
|
140
167
|
setOpen(false);
|
|
141
168
|
showToastHandler?.('success', 'Título criado com sucesso');
|
|
142
169
|
} catch {
|
|
@@ -146,9 +173,147 @@ function NovoTituloSheet({
|
|
|
146
173
|
|
|
147
174
|
const handleCancel = () => {
|
|
148
175
|
form.reset();
|
|
176
|
+
setUploadedFileId(null);
|
|
177
|
+
setUploadedFileName('');
|
|
178
|
+
setUploadProgress(0);
|
|
149
179
|
setOpen(false);
|
|
150
180
|
};
|
|
151
181
|
|
|
182
|
+
const uploadRelatedFile = async (file: File) => {
|
|
183
|
+
setIsUploadingFile(true);
|
|
184
|
+
setUploadProgress(0);
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
const formData = new FormData();
|
|
188
|
+
formData.append('file', file);
|
|
189
|
+
formData.append('destination', 'finance/titles');
|
|
190
|
+
|
|
191
|
+
const { data } = await request<{ id: number; filename: string }>({
|
|
192
|
+
url: '/file',
|
|
193
|
+
method: 'POST',
|
|
194
|
+
data: formData,
|
|
195
|
+
headers: {
|
|
196
|
+
'Content-Type': 'multipart/form-data',
|
|
197
|
+
},
|
|
198
|
+
onUploadProgress: (event) => {
|
|
199
|
+
if (!event.total) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const progress = Math.round((event.loaded * 100) / event.total);
|
|
204
|
+
setUploadProgress(progress);
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
if (!data?.id) {
|
|
209
|
+
throw new Error('Arquivo inválido');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
setUploadedFileId(data.id);
|
|
213
|
+
setUploadedFileName(
|
|
214
|
+
normalizeFilenameForDisplay(data.filename || file.name)
|
|
215
|
+
);
|
|
216
|
+
setUploadProgress(100);
|
|
217
|
+
showToastHandler?.('success', 'Arquivo relacionado com sucesso');
|
|
218
|
+
|
|
219
|
+
setIsExtractingFileData(true);
|
|
220
|
+
try {
|
|
221
|
+
const extraction = await request<{
|
|
222
|
+
documento?: string | null;
|
|
223
|
+
clienteId?: string;
|
|
224
|
+
competencia?: string;
|
|
225
|
+
vencimento?: string;
|
|
226
|
+
valor?: number | null;
|
|
227
|
+
categoriaId?: string;
|
|
228
|
+
centroCustoId?: string;
|
|
229
|
+
canal?: string;
|
|
230
|
+
descricao?: string | null;
|
|
231
|
+
}>({
|
|
232
|
+
url: '/finance/accounts-receivable/installments/extract-from-file',
|
|
233
|
+
method: 'POST',
|
|
234
|
+
data: {
|
|
235
|
+
file_id: data.id,
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const extracted = extraction.data || {};
|
|
240
|
+
|
|
241
|
+
if (extracted.documento) {
|
|
242
|
+
form.setValue('documento', extracted.documento, {
|
|
243
|
+
shouldValidate: true,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (extracted.clienteId) {
|
|
248
|
+
form.setValue('clienteId', extracted.clienteId, {
|
|
249
|
+
shouldValidate: true,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (extracted.competencia) {
|
|
254
|
+
form.setValue('competencia', extracted.competencia, {
|
|
255
|
+
shouldValidate: true,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (extracted.vencimento) {
|
|
260
|
+
form.setValue('vencimento', extracted.vencimento, {
|
|
261
|
+
shouldValidate: true,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (typeof extracted.valor === 'number' && extracted.valor > 0) {
|
|
266
|
+
form.setValue('valor', extracted.valor, {
|
|
267
|
+
shouldValidate: true,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (extracted.categoriaId) {
|
|
272
|
+
form.setValue('categoriaId', extracted.categoriaId, {
|
|
273
|
+
shouldValidate: true,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (extracted.centroCustoId) {
|
|
278
|
+
form.setValue('centroCustoId', extracted.centroCustoId, {
|
|
279
|
+
shouldValidate: true,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (extracted.canal) {
|
|
284
|
+
form.setValue('canal', extracted.canal, {
|
|
285
|
+
shouldValidate: true,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (extracted.descricao) {
|
|
290
|
+
form.setValue('descricao', extracted.descricao, {
|
|
291
|
+
shouldValidate: true,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
showToastHandler?.(
|
|
296
|
+
'success',
|
|
297
|
+
'Dados da fatura extraídos e preenchidos automaticamente'
|
|
298
|
+
);
|
|
299
|
+
} catch {
|
|
300
|
+
showToastHandler?.(
|
|
301
|
+
'error',
|
|
302
|
+
'Não foi possível extrair os dados automaticamente'
|
|
303
|
+
);
|
|
304
|
+
} finally {
|
|
305
|
+
setIsExtractingFileData(false);
|
|
306
|
+
}
|
|
307
|
+
} catch {
|
|
308
|
+
setUploadedFileId(null);
|
|
309
|
+
setUploadedFileName('');
|
|
310
|
+
setUploadProgress(0);
|
|
311
|
+
showToastHandler?.('error', 'Não foi possível enviar o arquivo');
|
|
312
|
+
} finally {
|
|
313
|
+
setIsUploadingFile(false);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
152
317
|
return (
|
|
153
318
|
<Sheet open={open} onOpenChange={setOpen}>
|
|
154
319
|
<SheetTrigger asChild>
|
|
@@ -165,6 +330,46 @@ function NovoTituloSheet({
|
|
|
165
330
|
<Form {...form}>
|
|
166
331
|
<form className="px-4" onSubmit={form.handleSubmit(handleSubmit)}>
|
|
167
332
|
<div className="grid gap-4">
|
|
333
|
+
<div className="grid gap-2">
|
|
334
|
+
<FormLabel>Arquivo da fatura (opcional)</FormLabel>
|
|
335
|
+
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
|
|
336
|
+
<Input
|
|
337
|
+
type="file"
|
|
338
|
+
accept=".pdf,.png,.jpg,.jpeg,.xml,.txt"
|
|
339
|
+
onChange={(event) => {
|
|
340
|
+
const file = event.target.files?.[0];
|
|
341
|
+
if (!file) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
setUploadedFileId(null);
|
|
346
|
+
setUploadedFileName('');
|
|
347
|
+
setUploadProgress(0);
|
|
348
|
+
void uploadRelatedFile(file);
|
|
349
|
+
}}
|
|
350
|
+
disabled={isUploadingFile || form.formState.isSubmitting}
|
|
351
|
+
/>
|
|
352
|
+
</div>
|
|
353
|
+
{isUploadingFile && (
|
|
354
|
+
<div className="space-y-1">
|
|
355
|
+
<Progress value={uploadProgress} className="h-2" />
|
|
356
|
+
<p className="text-xs text-muted-foreground">
|
|
357
|
+
Upload em andamento: {uploadProgress}%
|
|
358
|
+
</p>
|
|
359
|
+
</div>
|
|
360
|
+
)}
|
|
361
|
+
{uploadedFileId && (
|
|
362
|
+
<p className="text-xs text-muted-foreground">
|
|
363
|
+
Arquivo relacionado: {uploadedFileName}
|
|
364
|
+
</p>
|
|
365
|
+
)}
|
|
366
|
+
{isExtractingFileData && (
|
|
367
|
+
<p className="text-xs text-muted-foreground">
|
|
368
|
+
Extraindo dados da fatura com IA...
|
|
369
|
+
</p>
|
|
370
|
+
)}
|
|
371
|
+
</div>
|
|
372
|
+
|
|
168
373
|
<FormField
|
|
169
374
|
control={form.control}
|
|
170
375
|
name="documento"
|
|
@@ -285,37 +285,64 @@ function NovaContaSheet({
|
|
|
285
285
|
/>
|
|
286
286
|
</div>
|
|
287
287
|
|
|
288
|
-
<
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
<
|
|
294
|
-
|
|
288
|
+
<div className="grid grid-cols-2 gap-4">
|
|
289
|
+
<FormField
|
|
290
|
+
control={form.control}
|
|
291
|
+
name="tipo"
|
|
292
|
+
render={({ field }) => (
|
|
293
|
+
<FormItem>
|
|
294
|
+
<FormLabel>{t('fields.type')}</FormLabel>
|
|
295
|
+
<Select
|
|
296
|
+
value={field.value}
|
|
297
|
+
onValueChange={field.onChange}
|
|
298
|
+
>
|
|
299
|
+
<FormControl>
|
|
300
|
+
<SelectTrigger className="w-full">
|
|
301
|
+
<SelectValue placeholder={t('common.select')} />
|
|
302
|
+
</SelectTrigger>
|
|
303
|
+
</FormControl>
|
|
304
|
+
<SelectContent>
|
|
305
|
+
<SelectItem value="corrente">
|
|
306
|
+
{t('types.corrente')}
|
|
307
|
+
</SelectItem>
|
|
308
|
+
<SelectItem value="poupanca">
|
|
309
|
+
{t('types.poupanca')}
|
|
310
|
+
</SelectItem>
|
|
311
|
+
<SelectItem value="investimento">
|
|
312
|
+
{t('types.investimento')}
|
|
313
|
+
</SelectItem>
|
|
314
|
+
<SelectItem value="caixa">
|
|
315
|
+
{t('types.caixa')}
|
|
316
|
+
</SelectItem>
|
|
317
|
+
</SelectContent>
|
|
318
|
+
</Select>
|
|
319
|
+
<FormMessage />
|
|
320
|
+
</FormItem>
|
|
321
|
+
)}
|
|
322
|
+
/>
|
|
323
|
+
|
|
324
|
+
<FormField
|
|
325
|
+
control={form.control}
|
|
326
|
+
name="saldoInicial"
|
|
327
|
+
render={({ field }) => (
|
|
328
|
+
<FormItem>
|
|
329
|
+
<FormLabel>{t('fields.initialBalance')}</FormLabel>
|
|
295
330
|
<FormControl>
|
|
296
|
-
<
|
|
297
|
-
|
|
298
|
-
|
|
331
|
+
<InputMoney
|
|
332
|
+
ref={field.ref}
|
|
333
|
+
name={field.name}
|
|
334
|
+
value={field.value}
|
|
335
|
+
onBlur={field.onBlur}
|
|
336
|
+
onValueChange={(value) => field.onChange(value ?? 0)}
|
|
337
|
+
placeholder="0,00"
|
|
338
|
+
disabled={!!editingAccount}
|
|
339
|
+
/>
|
|
299
340
|
</FormControl>
|
|
300
|
-
<
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
{t('types.poupanca')}
|
|
306
|
-
</SelectItem>
|
|
307
|
-
<SelectItem value="investimento">
|
|
308
|
-
{t('types.investimento')}
|
|
309
|
-
</SelectItem>
|
|
310
|
-
<SelectItem value="caixa">
|
|
311
|
-
{t('types.caixa')}
|
|
312
|
-
</SelectItem>
|
|
313
|
-
</SelectContent>
|
|
314
|
-
</Select>
|
|
315
|
-
<FormMessage />
|
|
316
|
-
</FormItem>
|
|
317
|
-
)}
|
|
318
|
-
/>
|
|
341
|
+
<FormMessage />
|
|
342
|
+
</FormItem>
|
|
343
|
+
)}
|
|
344
|
+
/>
|
|
345
|
+
</div>
|
|
319
346
|
|
|
320
347
|
<FormField
|
|
321
348
|
control={form.control}
|
|
@@ -334,28 +361,6 @@ function NovaContaSheet({
|
|
|
334
361
|
</FormItem>
|
|
335
362
|
)}
|
|
336
363
|
/>
|
|
337
|
-
|
|
338
|
-
<FormField
|
|
339
|
-
control={form.control}
|
|
340
|
-
name="saldoInicial"
|
|
341
|
-
render={({ field }) => (
|
|
342
|
-
<FormItem>
|
|
343
|
-
<FormLabel>{t('fields.initialBalance')}</FormLabel>
|
|
344
|
-
<FormControl>
|
|
345
|
-
<InputMoney
|
|
346
|
-
ref={field.ref}
|
|
347
|
-
name={field.name}
|
|
348
|
-
value={field.value}
|
|
349
|
-
onBlur={field.onBlur}
|
|
350
|
-
onValueChange={(value) => field.onChange(value ?? 0)}
|
|
351
|
-
placeholder="0,00"
|
|
352
|
-
disabled={!!editingAccount}
|
|
353
|
-
/>
|
|
354
|
-
</FormControl>
|
|
355
|
-
<FormMessage />
|
|
356
|
-
</FormItem>
|
|
357
|
-
)}
|
|
358
|
-
/>
|
|
359
364
|
</div>
|
|
360
365
|
|
|
361
366
|
<div className="flex justify-end gap-2 pt-4">
|
|
@@ -412,6 +417,7 @@ export default function ContasBancariasPage() {
|
|
|
412
417
|
},
|
|
413
418
|
placeholderData: [],
|
|
414
419
|
});
|
|
420
|
+
const accounts = contasBancarias ?? [];
|
|
415
421
|
|
|
416
422
|
const tipoConfig = {
|
|
417
423
|
corrente: { label: t('types.corrente'), icon: Building2 },
|
|
@@ -420,11 +426,11 @@ export default function ContasBancariasPage() {
|
|
|
420
426
|
caixa: { label: t('types.caixa'), icon: Wallet },
|
|
421
427
|
};
|
|
422
428
|
|
|
423
|
-
const saldoTotal =
|
|
429
|
+
const saldoTotal = accounts
|
|
424
430
|
.filter((c) => c.ativo)
|
|
425
431
|
.reduce((acc, c) => acc + c.saldoAtual, 0);
|
|
426
432
|
|
|
427
|
-
const saldoConciliadoTotal =
|
|
433
|
+
const saldoConciliadoTotal = accounts
|
|
428
434
|
.filter((c) => c.ativo)
|
|
429
435
|
.reduce((acc, c) => acc + c.saldoConciliado, 0);
|
|
430
436
|
|
|
@@ -522,7 +528,7 @@ export default function ContasBancariasPage() {
|
|
|
522
528
|
</div>
|
|
523
529
|
<p className="text-xs text-muted-foreground">
|
|
524
530
|
{t('cards.activeAccounts', {
|
|
525
|
-
count:
|
|
531
|
+
count: accounts.filter((c) => c.ativo).length,
|
|
526
532
|
})}
|
|
527
533
|
</p>
|
|
528
534
|
</CardContent>
|
|
@@ -547,7 +553,7 @@ export default function ContasBancariasPage() {
|
|
|
547
553
|
</div>
|
|
548
554
|
|
|
549
555
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
550
|
-
{
|
|
556
|
+
{accounts.map((conta) => {
|
|
551
557
|
const tipo =
|
|
552
558
|
tipoConfig[conta.tipo as keyof typeof tipoConfig] ||
|
|
553
559
|
tipoConfig.corrente;
|
|
@@ -563,14 +569,25 @@ export default function ContasBancariasPage() {
|
|
|
563
569
|
<TipoIcon className="h-5 w-5" />
|
|
564
570
|
</div>
|
|
565
571
|
<div>
|
|
566
|
-
<
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
572
|
+
<div className="flex gap-4 items-center">
|
|
573
|
+
<CardTitle className="text-base">
|
|
574
|
+
{conta.banco}
|
|
575
|
+
</CardTitle>
|
|
576
|
+
{conta.descricao && (
|
|
577
|
+
<span className="block text-muted-foreground text-xs">
|
|
578
|
+
{conta.descricao}
|
|
579
|
+
</span>
|
|
580
|
+
)}
|
|
581
|
+
</div>
|
|
582
|
+
<CardDescription className="space-y-0.5">
|
|
583
|
+
{conta.agencia !== '-' && (
|
|
584
|
+
<span className="block">
|
|
585
|
+
{t('accountCard.bankAccount', {
|
|
570
586
|
agency: conta.agencia,
|
|
571
587
|
account: conta.conta,
|
|
572
|
-
})
|
|
573
|
-
|
|
588
|
+
})}
|
|
589
|
+
</span>
|
|
590
|
+
)}
|
|
574
591
|
</CardDescription>
|
|
575
592
|
</div>
|
|
576
593
|
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/finance",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.233",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -10,12 +10,13 @@
|
|
|
10
10
|
"@nestjs/jwt": "^11",
|
|
11
11
|
"@nestjs/mapped-types": "*",
|
|
12
12
|
"@hed-hog/api-locale": "0.0.11",
|
|
13
|
-
"@hed-hog/api-prisma": "0.0.4",
|
|
14
13
|
"@hed-hog/api-pagination": "0.0.5",
|
|
15
|
-
"@hed-hog/
|
|
16
|
-
"@hed-hog/api": "0.0.3",
|
|
14
|
+
"@hed-hog/api-prisma": "0.0.4",
|
|
17
15
|
"@hed-hog/api-types": "0.0.1",
|
|
18
|
-
"@hed-hog/
|
|
16
|
+
"@hed-hog/tag": "0.0.233",
|
|
17
|
+
"@hed-hog/api": "0.0.3",
|
|
18
|
+
"@hed-hog/contact": "0.0.233",
|
|
19
|
+
"@hed-hog/core": "0.0.233"
|
|
19
20
|
},
|
|
20
21
|
"exports": {
|
|
21
22
|
".": {
|
|
@@ -139,4 +139,16 @@ export class CreateFinancialTitleDto {
|
|
|
139
139
|
@ValidateNested({ each: true })
|
|
140
140
|
@Type(() => CreateFinancialInstallmentDto)
|
|
141
141
|
installments?: CreateFinancialInstallmentDto[];
|
|
142
|
+
|
|
143
|
+
@IsOptional()
|
|
144
|
+
@IsArray({
|
|
145
|
+
message: (args) =>
|
|
146
|
+
getLocaleText('validation.attachmentFileIdsMustBeArray', args.value),
|
|
147
|
+
})
|
|
148
|
+
@IsInt({
|
|
149
|
+
each: true,
|
|
150
|
+
message: (args) =>
|
|
151
|
+
getLocaleText('validation.attachmentFileIdMustBeNumber', args.value),
|
|
152
|
+
})
|
|
153
|
+
attachment_file_ids?: number[];
|
|
142
154
|
}
|
|
@@ -2,15 +2,19 @@ import { Role, User } from '@hed-hog/api';
|
|
|
2
2
|
import { Locale } from '@hed-hog/api-locale';
|
|
3
3
|
import { Pagination } from '@hed-hog/api-pagination';
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
Body,
|
|
6
|
+
Controller,
|
|
7
|
+
Get,
|
|
8
|
+
Param,
|
|
9
|
+
ParseIntPipe,
|
|
10
|
+
Post,
|
|
11
|
+
Query,
|
|
12
|
+
UploadedFile,
|
|
13
|
+
UseInterceptors,
|
|
12
14
|
} from '@nestjs/common';
|
|
15
|
+
import { FileInterceptor } from '@nestjs/platform-express';
|
|
13
16
|
import { CreateFinancialTitleDto } from './dto/create-financial-title.dto';
|
|
17
|
+
import { ExtractFinancialTitleFromFileDto } from './dto/extract-financial-title-from-file.dto';
|
|
14
18
|
import { FinanceService } from './finance.service';
|
|
15
19
|
|
|
16
20
|
@Role()
|
|
@@ -50,6 +54,15 @@ export class FinanceInstallmentsController {
|
|
|
50
54
|
);
|
|
51
55
|
}
|
|
52
56
|
|
|
57
|
+
@Post('accounts-payable/installments/extract-from-file')
|
|
58
|
+
@UseInterceptors(FileInterceptor('file'))
|
|
59
|
+
async extractAccountsPayableInfoFromFile(
|
|
60
|
+
@UploadedFile() file: MulterFile,
|
|
61
|
+
@Body() data: ExtractFinancialTitleFromFileDto,
|
|
62
|
+
) {
|
|
63
|
+
return this.financeService.getAgentExtractInfoFromFile(file, data.file_id);
|
|
64
|
+
}
|
|
65
|
+
|
|
53
66
|
@Get('accounts-receivable/installments')
|
|
54
67
|
async listAccountsReceivableInstallments(
|
|
55
68
|
@Pagination() paginationParams,
|
|
@@ -81,4 +94,17 @@ export class FinanceInstallmentsController {
|
|
|
81
94
|
user?.id,
|
|
82
95
|
);
|
|
83
96
|
}
|
|
97
|
+
|
|
98
|
+
@Post('accounts-receivable/installments/extract-from-file')
|
|
99
|
+
@UseInterceptors(FileInterceptor('file'))
|
|
100
|
+
async extractAccountsReceivableInfoFromFile(
|
|
101
|
+
@UploadedFile() file: MulterFile,
|
|
102
|
+
@Body() data: ExtractFinancialTitleFromFileDto,
|
|
103
|
+
) {
|
|
104
|
+
return this.financeService.getAgentExtractInfoFromFile(
|
|
105
|
+
file,
|
|
106
|
+
data.file_id,
|
|
107
|
+
'receivable',
|
|
108
|
+
);
|
|
109
|
+
}
|
|
84
110
|
}
|
package/src/finance.module.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LocaleModule } from '@hed-hog/api-locale';
|
|
2
2
|
import { PaginationModule } from '@hed-hog/api-pagination';
|
|
3
3
|
import { PrismaModule } from '@hed-hog/api-prisma';
|
|
4
|
+
import { AiModule } from '@hed-hog/core';
|
|
4
5
|
import { forwardRef, Module } from '@nestjs/common';
|
|
5
6
|
import { ConfigModule } from '@nestjs/config';
|
|
6
7
|
import { FinanceBankAccountsController } from './finance-bank-accounts.controller';
|
|
@@ -14,7 +15,8 @@ import { FinanceService } from './finance.service';
|
|
|
14
15
|
ConfigModule.forRoot(),
|
|
15
16
|
forwardRef(() => PaginationModule),
|
|
16
17
|
forwardRef(() => PrismaModule),
|
|
17
|
-
forwardRef(() => LocaleModule)
|
|
18
|
+
forwardRef(() => LocaleModule),
|
|
19
|
+
forwardRef(() => AiModule),
|
|
18
20
|
],
|
|
19
21
|
controllers: [
|
|
20
22
|
FinanceDataController,
|