@hed-hog/finance 0.0.274 → 0.0.276

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 (40) hide show
  1. package/README.md +228 -126
  2. package/dist/dto/create-bank-reconciliation.dto.d.ts +8 -0
  3. package/dist/dto/create-bank-reconciliation.dto.d.ts.map +1 -0
  4. package/dist/dto/create-bank-reconciliation.dto.js +43 -0
  5. package/dist/dto/create-bank-reconciliation.dto.js.map +1 -0
  6. package/dist/finance-data.controller.d.ts +2 -0
  7. package/dist/finance-data.controller.d.ts.map +1 -1
  8. package/dist/finance-statements.controller.d.ts +42 -0
  9. package/dist/finance-statements.controller.d.ts.map +1 -1
  10. package/dist/finance-statements.controller.js +13 -0
  11. package/dist/finance-statements.controller.js.map +1 -1
  12. package/dist/finance.service.d.ts +44 -0
  13. package/dist/finance.service.d.ts.map +1 -1
  14. package/dist/finance.service.js +98 -9
  15. package/dist/finance.service.js.map +1 -1
  16. package/hedhog/data/route.yaml +9 -0
  17. package/hedhog/frontend/app/_components/person-field-with-create.tsx.ejs +126 -126
  18. package/hedhog/frontend/app/accounts-payable/approvals/page.tsx.ejs +373 -373
  19. package/hedhog/frontend/app/accounts-payable/installments/[id]/page.tsx.ejs +1270 -1270
  20. package/hedhog/frontend/app/accounts-receivable/installments/[id]/page.tsx.ejs +982 -982
  21. package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +686 -686
  22. package/hedhog/frontend/app/cash-and-banks/bank-reconciliation/page.tsx.ejs +152 -32
  23. package/hedhog/frontend/app/cash-and-banks/statements/page.tsx.ejs +986 -986
  24. package/hedhog/frontend/app/cash-and-banks/transfers/page.tsx.ejs +492 -492
  25. package/hedhog/frontend/app/page.tsx.ejs +372 -372
  26. package/hedhog/frontend/app/planning/cash-flow-forecast/page.tsx.ejs +329 -329
  27. package/hedhog/frontend/app/planning/receivables-calendar/page.tsx.ejs +227 -227
  28. package/hedhog/frontend/app/planning/scenarios/page.tsx.ejs +408 -408
  29. package/hedhog/frontend/messages/en.json +15 -5
  30. package/hedhog/frontend/messages/pt.json +15 -5
  31. package/package.json +7 -7
  32. package/src/dto/create-bank-reconciliation.dto.ts +24 -0
  33. package/src/finance-statements.controller.ts +14 -0
  34. package/src/finance.module.ts +43 -43
  35. package/src/finance.service.ts +118 -0
  36. package/src/index.ts +14 -14
  37. package/dist/finance.controller.d.ts +0 -276
  38. package/dist/finance.controller.d.ts.map +0 -1
  39. package/dist/finance.controller.js +0 -110
  40. package/dist/finance.controller.js.map +0 -1
@@ -430,6 +430,15 @@
430
430
  - where:
431
431
  slug: admin-finance
432
432
 
433
+ - url: /finance/bank-reconciliations
434
+ method: POST
435
+ relations:
436
+ role:
437
+ - where:
438
+ slug: admin
439
+ - where:
440
+ slug: admin-finance
441
+
433
442
  - url: /finance/statements/export
434
443
  method: GET
435
444
  relations:
@@ -37,29 +37,29 @@ import {
37
37
  SheetHeader,
38
38
  SheetTitle,
39
39
  } from '@/components/ui/sheet';
40
- import { useApp, useQuery } from '@hed-hog/next-app-provider';
41
- import { zodResolver } from '@hookform/resolvers/zod';
42
- import { ChevronsUpDown, Plus, X } from 'lucide-react';
43
- import { useTranslations } from 'next-intl';
44
- import { useEffect, useMemo, useRef, useState } from 'react';
45
- import { FieldValues, Path, UseFormReturn, useForm } from 'react-hook-form';
46
- import { z } from 'zod';
40
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
41
+ import { zodResolver } from '@hookform/resolvers/zod';
42
+ import { ChevronsUpDown, Plus, X } from 'lucide-react';
43
+ import { useTranslations } from 'next-intl';
44
+ import { useEffect, useMemo, useRef, useState } from 'react';
45
+ import { FieldValues, Path, UseFormReturn, useForm } from 'react-hook-form';
46
+ import { z } from 'zod';
47
47
 
48
48
  type PersonOption = {
49
49
  id: number | string;
50
50
  name: string;
51
51
  };
52
52
 
53
- type CreatePersonValues = {
54
- name: string;
55
- type: 'individual' | 'company';
56
- email?: string;
57
- phone?: string;
58
- document?: string;
59
- line1?: string;
60
- city?: string;
61
- state?: string;
62
- };
53
+ type CreatePersonValues = {
54
+ name: string;
55
+ type: 'individual' | 'company';
56
+ email?: string;
57
+ phone?: string;
58
+ document?: string;
59
+ line1?: string;
60
+ city?: string;
61
+ state?: string;
62
+ };
63
63
 
64
64
  function CreatePersonSheet({
65
65
  open,
@@ -72,33 +72,33 @@ function CreatePersonSheet({
72
72
  onCreated: (person: PersonOption) => void;
73
73
  entityLabel: string;
74
74
  }) {
75
- const { request, showToastHandler, currentLocaleCode, getSettingValue } =
76
- useApp();
77
- const t = useTranslations('finance.PersonFieldWithCreate');
78
- const allowCompanyRegistration =
79
- getSettingValue('contact-allow-company-registration') !== false;
80
-
81
- const createPersonSchema = useMemo(
82
- () =>
83
- z.object({
84
- name: z.string().trim().min(2, 'Nome é obrigatório'),
85
- type: allowCompanyRegistration
86
- ? z.enum(['individual', 'company'])
87
- : z.literal('individual'),
88
- email: z
89
- .string()
90
- .trim()
91
- .email('E-mail inválido')
92
- .optional()
93
- .or(z.literal('')),
94
- phone: z.string().trim().optional(),
95
- document: z.string().trim().optional(),
96
- line1: z.string().optional(),
97
- city: z.string().optional(),
98
- state: z.string().optional(),
99
- }),
100
- [allowCompanyRegistration]
101
- );
75
+ const { request, showToastHandler, currentLocaleCode, getSettingValue } =
76
+ useApp();
77
+ const t = useTranslations('finance.PersonFieldWithCreate');
78
+ const allowCompanyRegistration =
79
+ getSettingValue('contact-allow-company-registration') !== false;
80
+
81
+ const createPersonSchema = useMemo(
82
+ () =>
83
+ z.object({
84
+ name: z.string().trim().min(2, 'Nome é obrigatório'),
85
+ type: allowCompanyRegistration
86
+ ? z.enum(['individual', 'company'])
87
+ : z.literal('individual'),
88
+ email: z
89
+ .string()
90
+ .trim()
91
+ .email('E-mail inválido')
92
+ .optional()
93
+ .or(z.literal('')),
94
+ phone: z.string().trim().optional(),
95
+ document: z.string().trim().optional(),
96
+ line1: z.string().optional(),
97
+ city: z.string().optional(),
98
+ state: z.string().optional(),
99
+ }),
100
+ [allowCompanyRegistration]
101
+ );
102
102
 
103
103
  const form = useForm<CreatePersonValues>({
104
104
  resolver: zodResolver(createPersonSchema),
@@ -114,13 +114,13 @@ function CreatePersonSheet({
114
114
  },
115
115
  });
116
116
 
117
- const selectedType = allowCompanyRegistration ? form.watch('type') : 'individual';
118
-
119
- useEffect(() => {
120
- if (!allowCompanyRegistration) {
121
- form.setValue('type', 'individual');
122
- }
123
- }, [allowCompanyRegistration, form]);
117
+ const selectedType = allowCompanyRegistration ? form.watch('type') : 'individual';
118
+
119
+ useEffect(() => {
120
+ if (!allowCompanyRegistration) {
121
+ form.setValue('type', 'individual');
122
+ }
123
+ }, [allowCompanyRegistration, form]);
124
124
 
125
125
  const { data: contactTypes = [] } = useQuery<any[]>({
126
126
  queryKey: ['person-field-contact-types', currentLocaleCode],
@@ -134,7 +134,7 @@ function CreatePersonSheet({
134
134
  placeholderData: (old) => old ?? [],
135
135
  });
136
136
 
137
- const { data: documentTypes = [] } = useQuery<any[]>({
137
+ const { data: documentTypes = [] } = useQuery<any[]>({
138
138
  queryKey: ['person-field-document-types', currentLocaleCode],
139
139
  queryFn: async () => {
140
140
  const response = await request<any>({
@@ -162,21 +162,21 @@ function CreatePersonSheet({
162
162
  return found?.document_type_id || documentTypes[0]?.document_type_id;
163
163
  };
164
164
 
165
- const resolveAddressType = () => 'residential';
166
-
167
- const handleSubmit = async (values: CreatePersonValues) => {
168
- try {
169
- const normalizedType = allowCompanyRegistration ? values.type : 'individual';
170
-
171
- const createResponse = await request<any>({
172
- url: '/person',
173
- method: 'POST',
174
- data: {
175
- name: values.name,
176
- type: normalizedType,
177
- status: 'active',
178
- },
179
- });
165
+ const resolveAddressType = () => 'residential';
166
+
167
+ const handleSubmit = async (values: CreatePersonValues) => {
168
+ try {
169
+ const normalizedType = allowCompanyRegistration ? values.type : 'individual';
170
+
171
+ const createResponse = await request<any>({
172
+ url: '/person',
173
+ method: 'POST',
174
+ data: {
175
+ name: values.name,
176
+ type: normalizedType,
177
+ status: 'active',
178
+ },
179
+ });
180
180
 
181
181
  const personId = Number(
182
182
  createResponse?.data?.id ?? createResponse?.data?.data?.id
@@ -187,12 +187,12 @@ function CreatePersonSheet({
187
187
  }
188
188
 
189
189
  const emailTypeId = resolveContactTypeId('EMAIL', 0);
190
- const phoneTypeId =
191
- resolveContactTypeId('PHONE', 1) || resolveContactTypeId('MOBILE', 1);
192
- const documentTypeId = resolveDocumentTypeId(
193
- normalizedType === 'individual' ? 'CPF' : 'CNPJ'
194
- );
195
- const addressType = resolveAddressType();
190
+ const phoneTypeId =
191
+ resolveContactTypeId('PHONE', 1) || resolveContactTypeId('MOBILE', 1);
192
+ const documentTypeId = resolveDocumentTypeId(
193
+ normalizedType === 'individual' ? 'CPF' : 'CNPJ'
194
+ );
195
+ const addressType = resolveAddressType();
196
196
 
197
197
  const contacts = [
198
198
  values.email && emailTypeId
@@ -220,28 +220,28 @@ function CreatePersonSheet({
220
220
  ]
221
221
  : [];
222
222
 
223
- const addresses =
224
- values.line1 && values.city && values.state
225
- ? [
226
- {
227
- line1: values.line1.trim(),
228
- city: values.city.trim(),
229
- state: values.state.trim(),
230
- is_primary: true,
231
- address_type: addressType,
232
- },
233
- ]
234
- : [];
223
+ const addresses =
224
+ values.line1 && values.city && values.state
225
+ ? [
226
+ {
227
+ line1: values.line1.trim(),
228
+ city: values.city.trim(),
229
+ state: values.state.trim(),
230
+ is_primary: true,
231
+ address_type: addressType,
232
+ },
233
+ ]
234
+ : [];
235
235
 
236
236
  await request({
237
237
  url: `/person/${personId}`,
238
238
  method: 'PATCH',
239
- data: {
240
- name: values.name,
241
- type: normalizedType,
242
- status: 'active',
243
- contacts,
244
- documents,
239
+ data: {
240
+ name: values.name,
241
+ type: normalizedType,
242
+ status: 'active',
243
+ contacts,
244
+ documents,
245
245
  addresses,
246
246
  },
247
247
  });
@@ -272,14 +272,14 @@ function CreatePersonSheet({
272
272
  className="w-full overflow-y-auto sm:max-w-xl"
273
273
  onCloseAutoFocus={(event) => event.preventDefault()}
274
274
  >
275
- <SheetHeader>
276
- <SheetTitle>{t('sheet.title', { entityLabel })}</SheetTitle>
277
- <SheetDescription>
278
- {allowCompanyRegistration
279
- ? t('sheet.description')
280
- : t('sheet.descriptionIndividualOnly')}
281
- </SheetDescription>
282
- </SheetHeader>
275
+ <SheetHeader>
276
+ <SheetTitle>{t('sheet.title', { entityLabel })}</SheetTitle>
277
+ <SheetDescription>
278
+ {allowCompanyRegistration
279
+ ? t('sheet.description')
280
+ : t('sheet.descriptionIndividualOnly')}
281
+ </SheetDescription>
282
+ </SheetHeader>
283
283
 
284
284
  <Form {...form}>
285
285
  <div className="space-y-4 p-4">
@@ -300,33 +300,33 @@ function CreatePersonSheet({
300
300
  )}
301
301
  />
302
302
 
303
- {allowCompanyRegistration ? (
304
- <FormField
305
- control={form.control}
306
- name="type"
307
- render={({ field }) => (
308
- <FormItem>
309
- <FormLabel>{t('fields.type')}</FormLabel>
310
- <Select value={field.value} onValueChange={field.onChange}>
311
- <FormControl>
312
- <SelectTrigger>
313
- <SelectValue placeholder={t('common.select')} />
314
- </SelectTrigger>
315
- </FormControl>
316
- <SelectContent>
317
- <SelectItem value="individual">
318
- {t('types.individual')}
319
- </SelectItem>
320
- <SelectItem value="company">
321
- {t('types.company')}
322
- </SelectItem>
323
- </SelectContent>
324
- </Select>
325
- <FormMessage />
326
- </FormItem>
327
- )}
328
- />
329
- ) : null}
303
+ {allowCompanyRegistration ? (
304
+ <FormField
305
+ control={form.control}
306
+ name="type"
307
+ render={({ field }) => (
308
+ <FormItem>
309
+ <FormLabel>{t('fields.type')}</FormLabel>
310
+ <Select value={field.value} onValueChange={field.onChange}>
311
+ <FormControl>
312
+ <SelectTrigger>
313
+ <SelectValue placeholder={t('common.select')} />
314
+ </SelectTrigger>
315
+ </FormControl>
316
+ <SelectContent>
317
+ <SelectItem value="individual">
318
+ {t('types.individual')}
319
+ </SelectItem>
320
+ <SelectItem value="company">
321
+ {t('types.company')}
322
+ </SelectItem>
323
+ </SelectContent>
324
+ </Select>
325
+ <FormMessage />
326
+ </FormItem>
327
+ )}
328
+ />
329
+ ) : null}
330
330
 
331
331
  <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
332
332
  <FormField