@hed-hog/finance 0.0.239 → 0.0.240
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -22
- package/dist/finance-installments.controller.d.ts +132 -0
- package/dist/finance-installments.controller.d.ts.map +1 -1
- package/dist/finance-installments.controller.js +52 -0
- package/dist/finance-installments.controller.js.map +1 -1
- package/dist/finance-statements.controller.d.ts +8 -0
- package/dist/finance-statements.controller.d.ts.map +1 -1
- package/dist/finance-statements.controller.js +40 -0
- package/dist/finance-statements.controller.js.map +1 -1
- package/dist/finance.module.d.ts.map +1 -1
- package/dist/finance.module.js +1 -0
- package/dist/finance.module.js.map +1 -1
- package/dist/finance.service.d.ts +160 -2
- package/dist/finance.service.d.ts.map +1 -1
- package/dist/finance.service.js +626 -8
- package/dist/finance.service.js.map +1 -1
- package/hedhog/data/route.yaml +54 -0
- package/hedhog/frontend/app/accounts-payable/installments/[id]/page.tsx.ejs +80 -4
- package/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +736 -13
- package/hedhog/frontend/app/accounts-receivable/installments/[id]/page.tsx.ejs +1 -1
- package/hedhog/frontend/app/accounts-receivable/installments/page.tsx.ejs +1 -3
- package/hedhog/frontend/app/cash-and-banks/statements/page.tsx.ejs +212 -60
- package/hedhog/frontend/messages/en.json +1 -0
- package/hedhog/frontend/messages/pt.json +1 -0
- package/hedhog/query/0_constraints.sql +2 -0
- package/hedhog/query/constraints.sql +86 -0
- package/hedhog/table/bank_account.yaml +0 -8
- package/hedhog/table/financial_title.yaml +1 -9
- package/hedhog/table/settlement.yaml +0 -8
- package/package.json +6 -6
- package/src/finance-installments.controller.ts +70 -10
- package/src/finance-statements.controller.ts +61 -2
- package/src/finance.module.ts +2 -1
- package/src/finance.service.ts +868 -12
- package/hedhog/table/branch.yaml +0 -18
|
@@ -378,7 +378,7 @@ export default function TituloReceberDetalhePage() {
|
|
|
378
378
|
};
|
|
379
379
|
|
|
380
380
|
const canApprove = titulo.status === 'rascunho';
|
|
381
|
-
const canSettle = ['
|
|
381
|
+
const canSettle = ['aberto', 'parcial'].includes(titulo.status);
|
|
382
382
|
|
|
383
383
|
const getErrorMessage = (error: any, fallback: string) => {
|
|
384
384
|
const message = error?.response?.data?.message;
|
|
@@ -1252,9 +1252,7 @@ export default function TitulosReceberPage() {
|
|
|
1252
1252
|
<DropdownMenuSeparator />
|
|
1253
1253
|
<DropdownMenuItem
|
|
1254
1254
|
disabled={
|
|
1255
|
-
!['
|
|
1256
|
-
titulo.status
|
|
1257
|
-
)
|
|
1255
|
+
!['aberto', 'parcial'].includes(titulo.status)
|
|
1258
1256
|
}
|
|
1259
1257
|
>
|
|
1260
1258
|
<Download className="mr-2 h-4 w-4" />
|
|
@@ -9,18 +9,16 @@ import {
|
|
|
9
9
|
CardHeader,
|
|
10
10
|
CardTitle,
|
|
11
11
|
} from '@/components/ui/card';
|
|
12
|
-
import {
|
|
13
|
-
Dialog,
|
|
14
|
-
DialogContent,
|
|
15
|
-
DialogDescription,
|
|
16
|
-
DialogFooter,
|
|
17
|
-
DialogHeader,
|
|
18
|
-
DialogTitle,
|
|
19
|
-
DialogTrigger,
|
|
20
|
-
} from '@/components/ui/dialog';
|
|
21
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';
|
|
22
21
|
import { Input } from '@/components/ui/input';
|
|
23
|
-
import { Label } from '@/components/ui/label';
|
|
24
22
|
import { Money } from '@/components/ui/money';
|
|
25
23
|
import {
|
|
26
24
|
Select,
|
|
@@ -29,6 +27,13 @@ import {
|
|
|
29
27
|
SelectTrigger,
|
|
30
28
|
SelectValue,
|
|
31
29
|
} from '@/components/ui/select';
|
|
30
|
+
import {
|
|
31
|
+
Sheet,
|
|
32
|
+
SheetContent,
|
|
33
|
+
SheetDescription,
|
|
34
|
+
SheetHeader,
|
|
35
|
+
SheetTitle,
|
|
36
|
+
} from '@/components/ui/sheet';
|
|
32
37
|
import { StatusBadge } from '@/components/ui/status-badge';
|
|
33
38
|
import {
|
|
34
39
|
Table,
|
|
@@ -39,10 +44,13 @@ import {
|
|
|
39
44
|
TableRow,
|
|
40
45
|
} from '@/components/ui/table';
|
|
41
46
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
47
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
42
48
|
import { ArrowDownRight, ArrowUpRight, Download, Upload } from 'lucide-react';
|
|
43
49
|
import { useTranslations } from 'next-intl';
|
|
44
50
|
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
45
51
|
import { useEffect, useMemo, useState } from 'react';
|
|
52
|
+
import { useForm } from 'react-hook-form';
|
|
53
|
+
import { z } from 'zod';
|
|
46
54
|
import { formatarData } from '../../_lib/formatters';
|
|
47
55
|
|
|
48
56
|
type BankAccount = {
|
|
@@ -67,64 +75,162 @@ type Statement = {
|
|
|
67
75
|
| 'ajustado';
|
|
68
76
|
};
|
|
69
77
|
|
|
70
|
-
|
|
78
|
+
const importStatementSchema = z.object({
|
|
79
|
+
bankAccountId: z.string().trim().min(1, 'Conta bancária é obrigatória'),
|
|
80
|
+
file: z.instanceof(File, { message: 'Arquivo é obrigatório' }).refine(
|
|
81
|
+
(value) => {
|
|
82
|
+
const fileName = value.name.toLowerCase();
|
|
83
|
+
return fileName.endsWith('.csv') || fileName.endsWith('.ofx');
|
|
84
|
+
},
|
|
85
|
+
{ message: 'Apenas arquivos CSV ou OFX são permitidos' }
|
|
86
|
+
),
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
type ImportStatementFormValues = z.infer<typeof importStatementSchema>;
|
|
90
|
+
|
|
91
|
+
function ImportarExtratoSheet({
|
|
71
92
|
contasBancarias,
|
|
72
93
|
t,
|
|
94
|
+
defaultBankAccountId,
|
|
95
|
+
onImported,
|
|
73
96
|
}: {
|
|
74
|
-
contasBancarias:
|
|
97
|
+
contasBancarias: BankAccount[];
|
|
75
98
|
t: ReturnType<typeof useTranslations>;
|
|
99
|
+
defaultBankAccountId?: string;
|
|
100
|
+
onImported: () => Promise<any> | void;
|
|
76
101
|
}) {
|
|
102
|
+
const { request, showToastHandler } = useApp();
|
|
103
|
+
const [open, setOpen] = useState(false);
|
|
104
|
+
|
|
105
|
+
const form = useForm<ImportStatementFormValues>({
|
|
106
|
+
resolver: zodResolver(importStatementSchema),
|
|
107
|
+
defaultValues: {
|
|
108
|
+
bankAccountId: defaultBankAccountId || '',
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (!open) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
form.reset({
|
|
118
|
+
bankAccountId: defaultBankAccountId || '',
|
|
119
|
+
file: undefined as unknown as File,
|
|
120
|
+
});
|
|
121
|
+
}, [defaultBankAccountId, form, open]);
|
|
122
|
+
|
|
123
|
+
const handleSubmit = async (values: ImportStatementFormValues) => {
|
|
124
|
+
const formData = new FormData();
|
|
125
|
+
formData.append('bank_account_id', values.bankAccountId);
|
|
126
|
+
formData.append('file', values.file);
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
await request({
|
|
130
|
+
url: '/finance/statements/import',
|
|
131
|
+
method: 'POST',
|
|
132
|
+
data: formData,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
await onImported();
|
|
136
|
+
showToastHandler?.('success', 'Extrato importado com sucesso');
|
|
137
|
+
setOpen(false);
|
|
138
|
+
} catch {
|
|
139
|
+
showToastHandler?.('error', 'Não foi possível importar o extrato');
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
77
143
|
return (
|
|
78
|
-
<
|
|
79
|
-
<
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
144
|
+
<Sheet open={open} onOpenChange={setOpen}>
|
|
145
|
+
<Button onClick={() => setOpen(true)}>
|
|
146
|
+
<Upload className="mr-2 h-4 w-4" />
|
|
147
|
+
{t('importDialog.action')}
|
|
148
|
+
</Button>
|
|
149
|
+
|
|
150
|
+
<SheetContent className="w-full sm:max-w-lg overflow-y-auto">
|
|
151
|
+
<SheetHeader>
|
|
152
|
+
<SheetTitle>{t('importDialog.title')}</SheetTitle>
|
|
153
|
+
<SheetDescription>{t('importDialog.description')}</SheetDescription>
|
|
154
|
+
</SheetHeader>
|
|
155
|
+
|
|
156
|
+
<Form {...form}>
|
|
157
|
+
<form
|
|
158
|
+
className="space-y-4 px-4"
|
|
159
|
+
onSubmit={form.handleSubmit(handleSubmit)}
|
|
160
|
+
>
|
|
161
|
+
<FormField
|
|
162
|
+
control={form.control}
|
|
163
|
+
name="bankAccountId"
|
|
164
|
+
render={({ field }) => (
|
|
165
|
+
<FormItem>
|
|
166
|
+
<FormLabel>{t('importDialog.bankAccount')}</FormLabel>
|
|
167
|
+
<Select value={field.value} onValueChange={field.onChange}>
|
|
168
|
+
<FormControl>
|
|
169
|
+
<SelectTrigger>
|
|
170
|
+
<SelectValue
|
|
171
|
+
placeholder={t('importDialog.selectAccount')}
|
|
172
|
+
/>
|
|
173
|
+
</SelectTrigger>
|
|
174
|
+
</FormControl>
|
|
175
|
+
<SelectContent>
|
|
176
|
+
{contasBancarias.map((conta) => (
|
|
177
|
+
<SelectItem key={conta.id} value={conta.id}>
|
|
178
|
+
{conta.banco} - {conta.descricao}
|
|
179
|
+
</SelectItem>
|
|
180
|
+
))}
|
|
181
|
+
</SelectContent>
|
|
182
|
+
</Select>
|
|
183
|
+
<FormMessage />
|
|
184
|
+
</FormItem>
|
|
185
|
+
)}
|
|
186
|
+
/>
|
|
187
|
+
|
|
188
|
+
<FormField
|
|
189
|
+
control={form.control}
|
|
190
|
+
name="file"
|
|
191
|
+
render={({ field }) => (
|
|
192
|
+
<FormItem>
|
|
193
|
+
<FormLabel>{t('importDialog.file')}</FormLabel>
|
|
194
|
+
<FormControl>
|
|
195
|
+
<Input
|
|
196
|
+
type="file"
|
|
197
|
+
accept=".ofx,.csv"
|
|
198
|
+
onChange={(event) => {
|
|
199
|
+
const selectedFile = event.target.files?.[0];
|
|
200
|
+
field.onChange(selectedFile);
|
|
201
|
+
}}
|
|
202
|
+
/>
|
|
203
|
+
</FormControl>
|
|
204
|
+
<p className="text-xs text-muted-foreground">
|
|
205
|
+
{t('importDialog.acceptedFormats')}
|
|
206
|
+
</p>
|
|
207
|
+
<FormMessage />
|
|
208
|
+
</FormItem>
|
|
209
|
+
)}
|
|
210
|
+
/>
|
|
211
|
+
|
|
212
|
+
<div className="flex justify-end gap-2 pt-2">
|
|
213
|
+
<Button
|
|
214
|
+
type="button"
|
|
215
|
+
variant="outline"
|
|
216
|
+
onClick={() => setOpen(false)}
|
|
217
|
+
>
|
|
218
|
+
{t('common.cancel')}
|
|
219
|
+
</Button>
|
|
220
|
+
<Button type="submit" disabled={form.formState.isSubmitting}>
|
|
221
|
+
{t('importDialog.submit')}
|
|
222
|
+
</Button>
|
|
223
|
+
</div>
|
|
224
|
+
</form>
|
|
225
|
+
</Form>
|
|
226
|
+
</SheetContent>
|
|
227
|
+
</Sheet>
|
|
122
228
|
);
|
|
123
229
|
}
|
|
124
230
|
|
|
125
231
|
export default function ExtratosPage() {
|
|
126
232
|
const t = useTranslations('finance.StatementsPage');
|
|
127
|
-
const { request } = useApp();
|
|
233
|
+
const { request, showToastHandler } = useApp();
|
|
128
234
|
const pathname = usePathname();
|
|
129
235
|
const router = useRouter();
|
|
130
236
|
const searchParams = useSearchParams();
|
|
@@ -179,7 +285,7 @@ export default function ExtratosPage() {
|
|
|
179
285
|
searchParams,
|
|
180
286
|
]);
|
|
181
287
|
|
|
182
|
-
const { data: extratos } = useQuery<Statement[]>({
|
|
288
|
+
const { data: extratos, refetch: refetchExtratos } = useQuery<Statement[]>({
|
|
183
289
|
queryKey: ['finance-statements', contaFilter],
|
|
184
290
|
queryFn: async () => {
|
|
185
291
|
if (!contaFilter) {
|
|
@@ -212,6 +318,47 @@ export default function ExtratosPage() {
|
|
|
212
318
|
.filter((e) => e.tipo === 'saida')
|
|
213
319
|
.reduce((acc, e) => acc + e.valor, 0);
|
|
214
320
|
|
|
321
|
+
const handleExport = async () => {
|
|
322
|
+
if (!contaFilter) {
|
|
323
|
+
showToastHandler?.('error', 'Selecione uma conta bancária para exportar');
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
try {
|
|
328
|
+
const response = await request<Blob>({
|
|
329
|
+
url: `/finance/statements/export?bank_account_id=${contaFilter}`,
|
|
330
|
+
method: 'GET',
|
|
331
|
+
responseType: 'blob',
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const contentDisposition =
|
|
335
|
+
response.headers?.['content-disposition'] ||
|
|
336
|
+
response.headers?.['Content-Disposition'];
|
|
337
|
+
const fileNameMatch =
|
|
338
|
+
typeof contentDisposition === 'string'
|
|
339
|
+
? contentDisposition.match(/filename\*?=(?:UTF-8'')?"?([^";]+)"?/i)
|
|
340
|
+
: null;
|
|
341
|
+
const fileName = fileNameMatch?.[1]
|
|
342
|
+
? decodeURIComponent(fileNameMatch[1])
|
|
343
|
+
: `extrato-bancario-${contaFilter}.csv`;
|
|
344
|
+
|
|
345
|
+
const blob = new Blob([response.data], {
|
|
346
|
+
type: 'text/csv;charset=utf-8;',
|
|
347
|
+
});
|
|
348
|
+
const url = window.URL.createObjectURL(blob);
|
|
349
|
+
const link = document.createElement('a');
|
|
350
|
+
|
|
351
|
+
link.href = url;
|
|
352
|
+
link.setAttribute('download', fileName);
|
|
353
|
+
document.body.appendChild(link);
|
|
354
|
+
link.click();
|
|
355
|
+
link.remove();
|
|
356
|
+
window.URL.revokeObjectURL(url);
|
|
357
|
+
} catch {
|
|
358
|
+
showToastHandler?.('error', 'Não foi possível exportar o extrato');
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
|
|
215
362
|
return (
|
|
216
363
|
<Page>
|
|
217
364
|
<PageHeader
|
|
@@ -224,11 +371,16 @@ export default function ExtratosPage() {
|
|
|
224
371
|
]}
|
|
225
372
|
actions={
|
|
226
373
|
<div className="flex gap-2">
|
|
227
|
-
<Button variant="outline">
|
|
374
|
+
<Button variant="outline" onClick={() => void handleExport()}>
|
|
228
375
|
<Download className="mr-2 h-4 w-4" />
|
|
229
376
|
{t('actions.export')}
|
|
230
377
|
</Button>
|
|
231
|
-
<
|
|
378
|
+
<ImportarExtratoSheet
|
|
379
|
+
contasBancarias={contasBancarias}
|
|
380
|
+
t={t}
|
|
381
|
+
defaultBankAccountId={contaFilter}
|
|
382
|
+
onImported={refetchExtratos}
|
|
383
|
+
/>
|
|
232
384
|
</div>
|
|
233
385
|
}
|
|
234
386
|
/>
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
-- Regras de integridade do módulo financeiro (PostgreSQL)
|
|
2
2
|
-- Script idempotente: pode ser executado mais de uma vez.
|
|
3
3
|
|
|
4
|
+
-- 0) Normalização de dados legados
|
|
5
|
+
-- Se existir título em status aprovado, converte para aberto.
|
|
6
|
+
UPDATE financial_title
|
|
7
|
+
SET status = 'open',
|
|
8
|
+
updated_at = NOW()
|
|
9
|
+
WHERE status::text = 'approved';
|
|
10
|
+
|
|
4
11
|
-- 1) CHECKs simples de domínio
|
|
5
12
|
DO $$
|
|
6
13
|
BEGIN
|
|
@@ -167,3 +174,82 @@ ON installment_allocation
|
|
|
167
174
|
DEFERRABLE INITIALLY DEFERRED
|
|
168
175
|
FOR EACH ROW
|
|
169
176
|
EXECUTE FUNCTION fn_check_installment_allocation_total_per_installment();
|
|
177
|
+
|
|
178
|
+
-- 4) Sincronização automática de status do título com base nas parcelas
|
|
179
|
+
-- Regras:
|
|
180
|
+
-- - Todas parcelas com open_amount_cents = 0 => settled
|
|
181
|
+
-- - Todas parcelas com open_amount_cents > 0 => open
|
|
182
|
+
-- - Mistura => partial
|
|
183
|
+
-- - Preserva títulos em draft e canceled
|
|
184
|
+
|
|
185
|
+
CREATE OR REPLACE FUNCTION finance_sync_title_status_from_installments()
|
|
186
|
+
RETURNS trigger
|
|
187
|
+
LANGUAGE plpgsql
|
|
188
|
+
AS $$
|
|
189
|
+
DECLARE
|
|
190
|
+
v_title_id BIGINT;
|
|
191
|
+
v_current_status financial_title_status;
|
|
192
|
+
v_total_installments INTEGER;
|
|
193
|
+
v_open_installments INTEGER;
|
|
194
|
+
v_settled_installments INTEGER;
|
|
195
|
+
v_next_status financial_title_status;
|
|
196
|
+
BEGIN
|
|
197
|
+
v_title_id := COALESCE(NEW.title_id, OLD.title_id);
|
|
198
|
+
|
|
199
|
+
IF v_title_id IS NULL THEN
|
|
200
|
+
RETURN COALESCE(NEW, OLD);
|
|
201
|
+
END IF;
|
|
202
|
+
|
|
203
|
+
SELECT status
|
|
204
|
+
INTO v_current_status
|
|
205
|
+
FROM financial_title
|
|
206
|
+
WHERE id = v_title_id;
|
|
207
|
+
|
|
208
|
+
IF v_current_status IS NULL THEN
|
|
209
|
+
RETURN COALESCE(NEW, OLD);
|
|
210
|
+
END IF;
|
|
211
|
+
|
|
212
|
+
IF v_current_status IN ('draft', 'canceled') THEN
|
|
213
|
+
RETURN COALESCE(NEW, OLD);
|
|
214
|
+
END IF;
|
|
215
|
+
|
|
216
|
+
SELECT COUNT(*)::INTEGER,
|
|
217
|
+
COUNT(*) FILTER (WHERE open_amount_cents > 0)::INTEGER,
|
|
218
|
+
COUNT(*) FILTER (WHERE open_amount_cents = 0)::INTEGER
|
|
219
|
+
INTO v_total_installments,
|
|
220
|
+
v_open_installments,
|
|
221
|
+
v_settled_installments
|
|
222
|
+
FROM financial_installment
|
|
223
|
+
WHERE title_id = v_title_id;
|
|
224
|
+
|
|
225
|
+
IF v_total_installments = 0 THEN
|
|
226
|
+
RETURN COALESCE(NEW, OLD);
|
|
227
|
+
END IF;
|
|
228
|
+
|
|
229
|
+
IF v_settled_installments = v_total_installments THEN
|
|
230
|
+
v_next_status := 'settled';
|
|
231
|
+
ELSIF v_open_installments = v_total_installments THEN
|
|
232
|
+
v_next_status := 'open';
|
|
233
|
+
ELSE
|
|
234
|
+
v_next_status := 'partial';
|
|
235
|
+
END IF;
|
|
236
|
+
|
|
237
|
+
IF v_current_status <> v_next_status THEN
|
|
238
|
+
UPDATE financial_title
|
|
239
|
+
SET status = v_next_status,
|
|
240
|
+
updated_at = NOW()
|
|
241
|
+
WHERE id = v_title_id;
|
|
242
|
+
END IF;
|
|
243
|
+
|
|
244
|
+
RETURN COALESCE(NEW, OLD);
|
|
245
|
+
END;
|
|
246
|
+
$$;
|
|
247
|
+
|
|
248
|
+
DROP TRIGGER IF EXISTS trg_financial_installment_sync_title_status
|
|
249
|
+
ON financial_installment;
|
|
250
|
+
|
|
251
|
+
CREATE TRIGGER trg_financial_installment_sync_title_status
|
|
252
|
+
AFTER INSERT OR UPDATE OF open_amount_cents, title_id OR DELETE
|
|
253
|
+
ON financial_installment
|
|
254
|
+
FOR EACH ROW
|
|
255
|
+
EXECUTE FUNCTION finance_sync_title_status_from_installments();
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
columns:
|
|
2
2
|
- type: pk
|
|
3
|
-
- name: branch_id
|
|
4
|
-
type: fk
|
|
5
|
-
isNullable: true
|
|
6
|
-
references:
|
|
7
|
-
table: branch
|
|
8
|
-
column: id
|
|
9
|
-
onDelete: SET NULL
|
|
10
|
-
onUpdate: CASCADE
|
|
11
3
|
- name: person_id
|
|
12
4
|
type: fk
|
|
13
5
|
references:
|
|
@@ -20,7 +12,7 @@ columns:
|
|
|
20
12
|
values: [payable, receivable]
|
|
21
13
|
- name: status
|
|
22
14
|
type: enum
|
|
23
|
-
values: [draft,
|
|
15
|
+
values: [draft, open, partial, settled, canceled, overdue]
|
|
24
16
|
- name: document_number
|
|
25
17
|
type: varchar
|
|
26
18
|
length: 80
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/finance",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.240",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
"@nestjs/core": "^11",
|
|
10
10
|
"@nestjs/jwt": "^11",
|
|
11
11
|
"@nestjs/mapped-types": "*",
|
|
12
|
-
"@hed-hog/
|
|
12
|
+
"@hed-hog/tag": "0.0.240",
|
|
13
13
|
"@hed-hog/api-pagination": "0.0.5",
|
|
14
|
+
"@hed-hog/api-prisma": "0.0.4",
|
|
14
15
|
"@hed-hog/api-locale": "0.0.11",
|
|
15
|
-
"@hed-hog/api-types": "0.0.1",
|
|
16
|
-
"@hed-hog/tag": "0.0.239",
|
|
17
16
|
"@hed-hog/api": "0.0.3",
|
|
18
|
-
"@hed-hog/contact": "0.0.
|
|
19
|
-
"@hed-hog/
|
|
17
|
+
"@hed-hog/contact": "0.0.240",
|
|
18
|
+
"@hed-hog/api-types": "0.0.1",
|
|
19
|
+
"@hed-hog/core": "0.0.240"
|
|
20
20
|
},
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
@@ -2,16 +2,16 @@ 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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
Body,
|
|
6
|
+
Controller,
|
|
7
|
+
Get,
|
|
8
|
+
Param,
|
|
9
|
+
ParseIntPipe,
|
|
10
|
+
Patch,
|
|
11
|
+
Post,
|
|
12
|
+
Query,
|
|
13
|
+
UploadedFile,
|
|
14
|
+
UseInterceptors,
|
|
15
15
|
} from '@nestjs/common';
|
|
16
16
|
import { FileInterceptor } from '@nestjs/platform-express';
|
|
17
17
|
import { CreateFinanceTagDto } from './dto/create-finance-tag.dto';
|
|
@@ -58,6 +58,21 @@ export class FinanceInstallmentsController {
|
|
|
58
58
|
);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
@Patch('accounts-payable/installments/:id')
|
|
62
|
+
async updateAccountsPayableTitle(
|
|
63
|
+
@Param('id', ParseIntPipe) id: number,
|
|
64
|
+
@Body() data: CreateFinancialTitleDto,
|
|
65
|
+
@Locale() locale: string,
|
|
66
|
+
@User() user,
|
|
67
|
+
) {
|
|
68
|
+
return this.financeService.updateAccountsPayableTitle(
|
|
69
|
+
id,
|
|
70
|
+
data,
|
|
71
|
+
locale,
|
|
72
|
+
user?.id,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
61
76
|
@Patch('accounts-payable/installments/:id/approve')
|
|
62
77
|
async approveAccountsPayableTitle(
|
|
63
78
|
@Param('id', ParseIntPipe) id: number,
|
|
@@ -82,6 +97,21 @@ export class FinanceInstallmentsController {
|
|
|
82
97
|
);
|
|
83
98
|
}
|
|
84
99
|
|
|
100
|
+
@Patch('accounts-payable/installments/:id/cancel')
|
|
101
|
+
async cancelAccountsPayableTitle(
|
|
102
|
+
@Param('id', ParseIntPipe) id: number,
|
|
103
|
+
@Body() data: RejectTitleDto,
|
|
104
|
+
@Locale() locale: string,
|
|
105
|
+
@User() user,
|
|
106
|
+
) {
|
|
107
|
+
return this.financeService.cancelAccountsPayableTitle(
|
|
108
|
+
id,
|
|
109
|
+
data,
|
|
110
|
+
locale,
|
|
111
|
+
user?.id,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
85
115
|
@Post('accounts-payable/installments/:id/settlements')
|
|
86
116
|
async settleAccountsPayableInstallment(
|
|
87
117
|
@Param('id', ParseIntPipe) id: number,
|
|
@@ -168,6 +198,21 @@ export class FinanceInstallmentsController {
|
|
|
168
198
|
);
|
|
169
199
|
}
|
|
170
200
|
|
|
201
|
+
@Patch('accounts-receivable/installments/:id')
|
|
202
|
+
async updateAccountsReceivableTitle(
|
|
203
|
+
@Param('id', ParseIntPipe) id: number,
|
|
204
|
+
@Body() data: CreateFinancialTitleDto,
|
|
205
|
+
@Locale() locale: string,
|
|
206
|
+
@User() user,
|
|
207
|
+
) {
|
|
208
|
+
return this.financeService.updateAccountsReceivableTitle(
|
|
209
|
+
id,
|
|
210
|
+
data,
|
|
211
|
+
locale,
|
|
212
|
+
user?.id,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
171
216
|
@Patch('accounts-receivable/installments/:id/approve')
|
|
172
217
|
async approveAccountsReceivableTitle(
|
|
173
218
|
@Param('id', ParseIntPipe) id: number,
|
|
@@ -181,6 +226,21 @@ export class FinanceInstallmentsController {
|
|
|
181
226
|
);
|
|
182
227
|
}
|
|
183
228
|
|
|
229
|
+
@Patch('accounts-receivable/installments/:id/cancel')
|
|
230
|
+
async cancelAccountsReceivableTitle(
|
|
231
|
+
@Param('id', ParseIntPipe) id: number,
|
|
232
|
+
@Body() data: RejectTitleDto,
|
|
233
|
+
@Locale() locale: string,
|
|
234
|
+
@User() user,
|
|
235
|
+
) {
|
|
236
|
+
return this.financeService.cancelAccountsReceivableTitle(
|
|
237
|
+
id,
|
|
238
|
+
data,
|
|
239
|
+
locale,
|
|
240
|
+
user?.id,
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
184
244
|
@Post('accounts-receivable/installments/:id/settlements')
|
|
185
245
|
async settleAccountsReceivableInstallment(
|
|
186
246
|
@Param('id', ParseIntPipe) id: number,
|