@hed-hog/finance 0.0.229 → 0.0.232
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/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +139 -4
- package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +157 -80
- package/hedhog/frontend/messages/en.json +14 -0
- package/hedhog/frontend/messages/pt.json +14 -0
- package/package.json +5 -5
- package/src/dto/create-financial-title.dto.ts +12 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-financial-title.dto.d.ts","sourceRoot":"","sources":["../../src/dto/create-financial-title.dto.ts"],"names":[],"mappings":"AAcA,qBAAa,6BAA6B;IAUxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAS5B,QAAQ,EAAE,MAAM,CAAC;IAajB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,uBAAuB;IAOlC,eAAe,EAAE,MAAM,CAAC;IAKxB,SAAS,EAAE,MAAM,CAAC;IAUlB,eAAe,CAAC,EAAE,MAAM,CAAC;IAUzB,UAAU,CAAC,EAAE,MAAM,CAAC;IASpB,QAAQ,EAAE,MAAM,CAAC;IAajB,YAAY,EAAE,MAAM,CAAC;IAOrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAO7B,cAAc,CAAC,EAAE,MAAM,CAAC;IAOxB,eAAe,CAAC,EAAE,MAAM,CAAC;IAOzB,WAAW,CAAC,EAAE,MAAM,CAAC;IASrB,YAAY,CAAC,EAAE,6BAA6B,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"create-financial-title.dto.d.ts","sourceRoot":"","sources":["../../src/dto/create-financial-title.dto.ts"],"names":[],"mappings":"AAcA,qBAAa,6BAA6B;IAUxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAS5B,QAAQ,EAAE,MAAM,CAAC;IAajB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,uBAAuB;IAOlC,eAAe,EAAE,MAAM,CAAC;IAKxB,SAAS,EAAE,MAAM,CAAC;IAUlB,eAAe,CAAC,EAAE,MAAM,CAAC;IAUzB,UAAU,CAAC,EAAE,MAAM,CAAC;IASpB,QAAQ,EAAE,MAAM,CAAC;IAajB,YAAY,EAAE,MAAM,CAAC;IAOrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAO7B,cAAc,CAAC,EAAE,MAAM,CAAC;IAOxB,eAAe,CAAC,EAAE,MAAM,CAAC;IAOzB,WAAW,CAAC,EAAE,MAAM,CAAC;IASrB,YAAY,CAAC,EAAE,6BAA6B,EAAE,CAAC;IAY/C,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC"}
|
|
@@ -125,4 +125,15 @@ __decorate([
|
|
|
125
125
|
(0, class_transformer_1.Type)(() => CreateFinancialInstallmentDto),
|
|
126
126
|
__metadata("design:type", Array)
|
|
127
127
|
], CreateFinancialTitleDto.prototype, "installments", void 0);
|
|
128
|
+
__decorate([
|
|
129
|
+
(0, class_validator_1.IsOptional)(),
|
|
130
|
+
(0, class_validator_1.IsArray)({
|
|
131
|
+
message: (args) => (0, api_locale_1.getLocaleText)('validation.attachmentFileIdsMustBeArray', args.value),
|
|
132
|
+
}),
|
|
133
|
+
(0, class_validator_1.IsInt)({
|
|
134
|
+
each: true,
|
|
135
|
+
message: (args) => (0, api_locale_1.getLocaleText)('validation.attachmentFileIdMustBeNumber', args.value),
|
|
136
|
+
}),
|
|
137
|
+
__metadata("design:type", Array)
|
|
138
|
+
], CreateFinancialTitleDto.prototype, "attachment_file_ids", void 0);
|
|
128
139
|
//# sourceMappingURL=create-financial-title.dto.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-financial-title.dto.js","sourceRoot":"","sources":["../../src/dto/create-financial-title.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oDAAoD;AACpD,yDAAyC;AACzC,qDAUyB;AAEzB,MAAa,6BAA6B;CAiCzC;AAjCD,sEAiCC;AAvBC;IATC,IAAA,4BAAU,GAAE;IACZ,IAAA,uBAAK,EAAC;QACL,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,0CAA0C,EAAE,IAAI,CAAC,KAAK,CAAC;KACxE,CAAC;IACD,IAAA,qBAAG,EAAC,CAAC,EAAE;QACN,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,iCAAiC,EAAE,IAAI,CAAC,KAAK,CAAC;KAC/D,CAAC;;yEAC0B;AAS5B;IAPC,IAAA,8BAAY,EACX,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,8BAA8B,EAAE,IAAI,CAAC,KAAK,CAAC;KAC5D,CACF;;+DACgB;AAajB;IAXC,IAAA,0BAAQ,EACP,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,0CAA0C,EAAE,IAAI,CAAC,KAAK,CAAC;KACxE,CACF;IACA,IAAA,qBAAG,EAAC,IAAI,EAAE;QACT,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,iCAAiC,EAAE,IAAI,CAAC,KAAK,CAAC;KAC/D,CAAC;;6DACa;AAGjB,MAAa,uBAAuB;
|
|
1
|
+
{"version":3,"file":"create-financial-title.dto.js","sourceRoot":"","sources":["../../src/dto/create-financial-title.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oDAAoD;AACpD,yDAAyC;AACzC,qDAUyB;AAEzB,MAAa,6BAA6B;CAiCzC;AAjCD,sEAiCC;AAvBC;IATC,IAAA,4BAAU,GAAE;IACZ,IAAA,uBAAK,EAAC;QACL,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,0CAA0C,EAAE,IAAI,CAAC,KAAK,CAAC;KACxE,CAAC;IACD,IAAA,qBAAG,EAAC,CAAC,EAAE;QACN,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,iCAAiC,EAAE,IAAI,CAAC,KAAK,CAAC;KAC/D,CAAC;;yEAC0B;AAS5B;IAPC,IAAA,8BAAY,EACX,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,8BAA8B,EAAE,IAAI,CAAC,KAAK,CAAC;KAC5D,CACF;;+DACgB;AAajB;IAXC,IAAA,0BAAQ,EACP,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,0CAA0C,EAAE,IAAI,CAAC,KAAK,CAAC;KACxE,CACF;IACA,IAAA,qBAAG,EAAC,IAAI,EAAE;QACT,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,iCAAiC,EAAE,IAAI,CAAC,KAAK,CAAC;KAC/D,CAAC;;6DACa;AAGjB,MAAa,uBAAuB;CAwGnC;AAxGD,0DAwGC;AAjGC;IANC,IAAA,0BAAQ,EAAC;QACR,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,0BAAa,EAAC,iCAAiC,EAAE,IAAI,CAAC,KAAK,CAAC;KAChF,CAAC;IACD,IAAA,4BAAU,EAAC;QACV,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,0BAAa,EAAC,6BAA6B,EAAE,IAAI,CAAC,KAAK,CAAC;KAC5E,CAAC;;gEACsB;AAKxB;IAHC,IAAA,uBAAK,EAAC;QACL,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,0BAAa,EAAC,iCAAiC,EAAE,IAAI,CAAC,KAAK,CAAC;KAChF,CAAC;;0DACgB;AAUlB;IARC,IAAA,4BAAU,GAAE;IACZ,IAAA,8BAAY,EACX,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,qCAAqC,EAAE,IAAI,CAAC,KAAK,CAAC;KACnE,CACF;;gEACwB;AAUzB;IARC,IAAA,4BAAU,GAAE;IACZ,IAAA,8BAAY,EACX,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,gCAAgC,EAAE,IAAI,CAAC,KAAK,CAAC;KAC9D,CACF;;2DACmB;AASpB;IAPC,IAAA,8BAAY,EACX,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,8BAA8B,EAAE,IAAI,CAAC,KAAK,CAAC;KAC5D,CACF;;yDACgB;AAajB;IAXC,IAAA,0BAAQ,EACP,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,oCAAoC,EAAE,IAAI,CAAC,KAAK,CAAC;KAClE,CACF;IACA,IAAA,qBAAG,EAAC,IAAI,EAAE;QACT,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,2BAA2B,EAAE,IAAI,CAAC,KAAK,CAAC;KACzD,CAAC;;6DACmB;AAOrB;IALC,IAAA,4BAAU,GAAE;IACZ,IAAA,uBAAK,EAAC;QACL,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,0CAA0C,EAAE,IAAI,CAAC,KAAK,CAAC;KACxE,CAAC;;oEAC2B;AAO7B;IALC,IAAA,4BAAU,GAAE;IACZ,IAAA,uBAAK,EAAC;QACL,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,qCAAqC,EAAE,IAAI,CAAC,KAAK,CAAC;KACnE,CAAC;;+DACsB;AAOxB;IALC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,EAAC;QACR,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,uCAAuC,EAAE,IAAI,CAAC,KAAK,CAAC;KACrE,CAAC;;gEACuB;AAOzB;IALC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,EAAC;QACR,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,oCAAoC,EAAE,IAAI,CAAC,KAAK,CAAC;KAClE,CAAC;;4DACmB;AASrB;IAPC,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,EAAC;QACP,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,oCAAoC,EAAE,IAAI,CAAC,KAAK,CAAC;KAClE,CAAC;IACD,IAAA,gCAAc,EAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC9B,IAAA,wBAAI,EAAC,GAAG,EAAE,CAAC,6BAA6B,CAAC;;6DACK;AAY/C;IAVC,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,EAAC;QACP,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,yCAAyC,EAAE,IAAI,CAAC,KAAK,CAAC;KACvE,CAAC;IACD,IAAA,uBAAK,EAAC;QACL,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,yCAAyC,EAAE,IAAI,CAAC,KAAK,CAAC;KACvE,CAAC;;oEAC6B"}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
import { Input } from '@/components/ui/input';
|
|
22
22
|
import { InputMoney } from '@/components/ui/input-money';
|
|
23
23
|
import { Money } from '@/components/ui/money';
|
|
24
|
+
import { Progress } from '@/components/ui/progress';
|
|
24
25
|
import {
|
|
25
26
|
Select,
|
|
26
27
|
SelectContent,
|
|
@@ -96,6 +97,28 @@ function NovoTituloSheet({
|
|
|
96
97
|
}) {
|
|
97
98
|
const { request, showToastHandler } = useApp();
|
|
98
99
|
const [open, setOpen] = useState(false);
|
|
100
|
+
const [uploadedFileId, setUploadedFileId] = useState<number | null>(null);
|
|
101
|
+
const [uploadedFileName, setUploadedFileName] = useState('');
|
|
102
|
+
const [isUploadingFile, setIsUploadingFile] = 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
|
+
};
|
|
99
122
|
|
|
100
123
|
const form = useForm<NewTitleFormValues>({
|
|
101
124
|
resolver: zodResolver(newTitleFormSchema),
|
|
@@ -133,11 +156,14 @@ function NovoTituloSheet({
|
|
|
133
156
|
: undefined,
|
|
134
157
|
payment_channel: values.metodo || undefined,
|
|
135
158
|
description: values.descricao?.trim() || undefined,
|
|
159
|
+
attachment_file_ids: uploadedFileId ? [uploadedFileId] : undefined,
|
|
136
160
|
},
|
|
137
161
|
});
|
|
138
162
|
|
|
139
163
|
await onCreated();
|
|
140
164
|
form.reset();
|
|
165
|
+
setUploadedFileId(null);
|
|
166
|
+
setUploadedFileName('');
|
|
141
167
|
setOpen(false);
|
|
142
168
|
showToastHandler?.('success', 'Título criado com sucesso');
|
|
143
169
|
} catch {
|
|
@@ -147,9 +173,83 @@ function NovoTituloSheet({
|
|
|
147
173
|
|
|
148
174
|
const handleCancel = () => {
|
|
149
175
|
form.reset();
|
|
176
|
+
setUploadedFileId(null);
|
|
177
|
+
setUploadedFileName('');
|
|
178
|
+
setUploadProgress(0);
|
|
150
179
|
setOpen(false);
|
|
151
180
|
};
|
|
152
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
|
+
} catch {
|
|
219
|
+
setUploadedFileId(null);
|
|
220
|
+
setUploadedFileName('');
|
|
221
|
+
setUploadProgress(0);
|
|
222
|
+
showToastHandler?.('error', 'Não foi possível enviar o arquivo');
|
|
223
|
+
} finally {
|
|
224
|
+
setIsUploadingFile(false);
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const parseDateToIso = (value: string) => {
|
|
229
|
+
const sanitized = value.trim();
|
|
230
|
+
|
|
231
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(sanitized)) {
|
|
232
|
+
return sanitized;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const br = sanitized.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
|
|
236
|
+
if (br) {
|
|
237
|
+
return `${br[3]}-${br[2]}-${br[1]}`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return '';
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const parseMoneyToNumber = (value: string) => {
|
|
244
|
+
const normalized = value
|
|
245
|
+
.replace(/\s/g, '')
|
|
246
|
+
.replace(/\./g, '')
|
|
247
|
+
.replace(',', '.');
|
|
248
|
+
|
|
249
|
+
const parsed = Number(normalized);
|
|
250
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
251
|
+
};
|
|
252
|
+
|
|
153
253
|
return (
|
|
154
254
|
<Sheet open={open} onOpenChange={setOpen}>
|
|
155
255
|
<SheetTrigger asChild>
|
|
@@ -166,6 +266,41 @@ function NovoTituloSheet({
|
|
|
166
266
|
<Form {...form}>
|
|
167
267
|
<form className="px-4" onSubmit={form.handleSubmit(handleSubmit)}>
|
|
168
268
|
<div className="grid gap-4">
|
|
269
|
+
<div className="grid gap-2">
|
|
270
|
+
<FormLabel>Arquivo da fatura (opcional)</FormLabel>
|
|
271
|
+
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
|
|
272
|
+
<Input
|
|
273
|
+
type="file"
|
|
274
|
+
accept=".pdf,.png,.jpg,.jpeg,.xml,.txt"
|
|
275
|
+
onChange={(event) => {
|
|
276
|
+
const file = event.target.files?.[0];
|
|
277
|
+
if (!file) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
setUploadedFileId(null);
|
|
282
|
+
setUploadedFileName('');
|
|
283
|
+
setUploadProgress(0);
|
|
284
|
+
void uploadRelatedFile(file);
|
|
285
|
+
}}
|
|
286
|
+
disabled={isUploadingFile || form.formState.isSubmitting}
|
|
287
|
+
/>
|
|
288
|
+
</div>
|
|
289
|
+
{isUploadingFile && (
|
|
290
|
+
<div className="space-y-1">
|
|
291
|
+
<Progress value={uploadProgress} className="h-2" />
|
|
292
|
+
<p className="text-xs text-muted-foreground">
|
|
293
|
+
Upload em andamento: {uploadProgress}%
|
|
294
|
+
</p>
|
|
295
|
+
</div>
|
|
296
|
+
)}
|
|
297
|
+
{uploadedFileId && (
|
|
298
|
+
<p className="text-xs text-muted-foreground">
|
|
299
|
+
Arquivo relacionado: {uploadedFileName}
|
|
300
|
+
</p>
|
|
301
|
+
)}
|
|
302
|
+
</div>
|
|
303
|
+
|
|
169
304
|
<FormField
|
|
170
305
|
control={form.control}
|
|
171
306
|
name="documento"
|
|
@@ -188,7 +323,7 @@ function NovoTituloSheet({
|
|
|
188
323
|
<FormLabel>{t('fields.supplier')}</FormLabel>
|
|
189
324
|
<Select value={field.value} onValueChange={field.onChange}>
|
|
190
325
|
<FormControl>
|
|
191
|
-
<SelectTrigger>
|
|
326
|
+
<SelectTrigger className="w-full">
|
|
192
327
|
<SelectValue placeholder={t('common.select')} />
|
|
193
328
|
</SelectTrigger>
|
|
194
329
|
</FormControl>
|
|
@@ -276,7 +411,7 @@ function NovoTituloSheet({
|
|
|
276
411
|
<FormLabel>{t('fields.category')}</FormLabel>
|
|
277
412
|
<Select value={field.value} onValueChange={field.onChange}>
|
|
278
413
|
<FormControl>
|
|
279
|
-
<SelectTrigger>
|
|
414
|
+
<SelectTrigger className="w-full">
|
|
280
415
|
<SelectValue placeholder={t('common.select')} />
|
|
281
416
|
</SelectTrigger>
|
|
282
417
|
</FormControl>
|
|
@@ -303,7 +438,7 @@ function NovoTituloSheet({
|
|
|
303
438
|
<FormLabel>{t('fields.costCenter')}</FormLabel>
|
|
304
439
|
<Select value={field.value} onValueChange={field.onChange}>
|
|
305
440
|
<FormControl>
|
|
306
|
-
<SelectTrigger>
|
|
441
|
+
<SelectTrigger className="w-full">
|
|
307
442
|
<SelectValue placeholder={t('common.select')} />
|
|
308
443
|
</SelectTrigger>
|
|
309
444
|
</FormControl>
|
|
@@ -328,7 +463,7 @@ function NovoTituloSheet({
|
|
|
328
463
|
<FormLabel>{t('fields.paymentMethod')}</FormLabel>
|
|
329
464
|
<Select value={field.value} onValueChange={field.onChange}>
|
|
330
465
|
<FormControl>
|
|
331
|
-
<SelectTrigger>
|
|
466
|
+
<SelectTrigger className="w-full">
|
|
332
467
|
<SelectValue placeholder={t('common.select')} />
|
|
333
468
|
</SelectTrigger>
|
|
334
469
|
</FormControl>
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { Page, PageHeader } from '@/components/entity-list';
|
|
4
|
+
import {
|
|
5
|
+
AlertDialog,
|
|
6
|
+
AlertDialogAction,
|
|
7
|
+
AlertDialogCancel,
|
|
8
|
+
AlertDialogContent,
|
|
9
|
+
AlertDialogDescription,
|
|
10
|
+
AlertDialogFooter,
|
|
11
|
+
AlertDialogHeader,
|
|
12
|
+
AlertDialogTitle,
|
|
13
|
+
} from '@/components/ui/alert-dialog';
|
|
4
14
|
import { Badge } from '@/components/ui/badge';
|
|
5
15
|
import { Button } from '@/components/ui/button';
|
|
6
16
|
import {
|
|
@@ -97,6 +107,19 @@ function NovaContaSheet({
|
|
|
97
107
|
}) {
|
|
98
108
|
const { request, showToastHandler } = useApp();
|
|
99
109
|
|
|
110
|
+
const createSuccessMessage = t.has('messages.createSuccess')
|
|
111
|
+
? t('messages.createSuccess')
|
|
112
|
+
: 'Conta bancária cadastrada com sucesso';
|
|
113
|
+
const createErrorMessage = t.has('messages.createError')
|
|
114
|
+
? t('messages.createError')
|
|
115
|
+
: 'Erro ao cadastrar conta bancária';
|
|
116
|
+
const updateSuccessMessage = t.has('messages.updateSuccess')
|
|
117
|
+
? t('messages.updateSuccess')
|
|
118
|
+
: 'Conta bancária atualizada com sucesso';
|
|
119
|
+
const updateErrorMessage = t.has('messages.updateError')
|
|
120
|
+
? t('messages.updateError')
|
|
121
|
+
: 'Erro ao atualizar conta bancária';
|
|
122
|
+
|
|
100
123
|
const form = useForm<BankAccountFormValues>({
|
|
101
124
|
resolver: zodResolver(bankAccountFormSchema),
|
|
102
125
|
defaultValues: {
|
|
@@ -171,16 +194,12 @@ function NovaContaSheet({
|
|
|
171
194
|
onEditingAccountChange(null);
|
|
172
195
|
showToastHandler?.(
|
|
173
196
|
'success',
|
|
174
|
-
editingAccount
|
|
175
|
-
? 'Conta bancária atualizada com sucesso'
|
|
176
|
-
: 'Conta bancária cadastrada com sucesso'
|
|
197
|
+
editingAccount ? updateSuccessMessage : createSuccessMessage
|
|
177
198
|
);
|
|
178
199
|
} catch {
|
|
179
200
|
showToastHandler?.(
|
|
180
201
|
'error',
|
|
181
|
-
editingAccount
|
|
182
|
-
? 'Erro ao atualizar conta bancária'
|
|
183
|
-
: 'Erro ao cadastrar conta bancária'
|
|
202
|
+
editingAccount ? updateErrorMessage : createErrorMessage
|
|
184
203
|
);
|
|
185
204
|
}
|
|
186
205
|
};
|
|
@@ -266,37 +285,64 @@ function NovaContaSheet({
|
|
|
266
285
|
/>
|
|
267
286
|
</div>
|
|
268
287
|
|
|
269
|
-
<
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
<
|
|
275
|
-
|
|
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>
|
|
276
330
|
<FormControl>
|
|
277
|
-
<
|
|
278
|
-
|
|
279
|
-
|
|
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
|
+
/>
|
|
280
340
|
</FormControl>
|
|
281
|
-
<
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
{t('types.poupanca')}
|
|
287
|
-
</SelectItem>
|
|
288
|
-
<SelectItem value="investimento">
|
|
289
|
-
{t('types.investimento')}
|
|
290
|
-
</SelectItem>
|
|
291
|
-
<SelectItem value="caixa">
|
|
292
|
-
{t('types.caixa')}
|
|
293
|
-
</SelectItem>
|
|
294
|
-
</SelectContent>
|
|
295
|
-
</Select>
|
|
296
|
-
<FormMessage />
|
|
297
|
-
</FormItem>
|
|
298
|
-
)}
|
|
299
|
-
/>
|
|
341
|
+
<FormMessage />
|
|
342
|
+
</FormItem>
|
|
343
|
+
)}
|
|
344
|
+
/>
|
|
345
|
+
</div>
|
|
300
346
|
|
|
301
347
|
<FormField
|
|
302
348
|
control={form.control}
|
|
@@ -315,28 +361,6 @@ function NovaContaSheet({
|
|
|
315
361
|
</FormItem>
|
|
316
362
|
)}
|
|
317
363
|
/>
|
|
318
|
-
|
|
319
|
-
<FormField
|
|
320
|
-
control={form.control}
|
|
321
|
-
name="saldoInicial"
|
|
322
|
-
render={({ field }) => (
|
|
323
|
-
<FormItem>
|
|
324
|
-
<FormLabel>{t('fields.initialBalance')}</FormLabel>
|
|
325
|
-
<FormControl>
|
|
326
|
-
<InputMoney
|
|
327
|
-
ref={field.ref}
|
|
328
|
-
name={field.name}
|
|
329
|
-
value={field.value}
|
|
330
|
-
onBlur={field.onBlur}
|
|
331
|
-
onValueChange={(value) => field.onChange(value ?? 0)}
|
|
332
|
-
placeholder="0,00"
|
|
333
|
-
disabled={!!editingAccount}
|
|
334
|
-
/>
|
|
335
|
-
</FormControl>
|
|
336
|
-
<FormMessage />
|
|
337
|
-
</FormItem>
|
|
338
|
-
)}
|
|
339
|
-
/>
|
|
340
364
|
</div>
|
|
341
365
|
|
|
342
366
|
<div className="flex justify-end gap-2 pt-4">
|
|
@@ -356,13 +380,33 @@ function NovaContaSheet({
|
|
|
356
380
|
|
|
357
381
|
export default function ContasBancariasPage() {
|
|
358
382
|
const t = useTranslations('finance.BankAccountsPage');
|
|
359
|
-
const { request, showToastHandler } = useApp();
|
|
383
|
+
const { request, showToastHandler, currentLocaleCode } = useApp();
|
|
384
|
+
|
|
385
|
+
const deleteSuccessMessage = t.has('messages.deleteSuccess')
|
|
386
|
+
? t('messages.deleteSuccess')
|
|
387
|
+
: 'Conta bancária inativada com sucesso';
|
|
388
|
+
const deleteErrorMessage = t.has('messages.deleteError')
|
|
389
|
+
? t('messages.deleteError')
|
|
390
|
+
: 'Erro ao inativar conta bancária';
|
|
391
|
+
const deleteDialogTitle = t.has('deleteDialog.title')
|
|
392
|
+
? t('deleteDialog.title')
|
|
393
|
+
: 'Inativar conta bancária';
|
|
394
|
+
const deleteDialogDescription = t.has('deleteDialog.description')
|
|
395
|
+
? t('deleteDialog.description')
|
|
396
|
+
: 'Deseja realmente inativar esta conta bancária?';
|
|
397
|
+
const deleteDialogConfirm = t.has('deleteDialog.confirm')
|
|
398
|
+
? t('deleteDialog.confirm')
|
|
399
|
+
: 'Inativar';
|
|
400
|
+
|
|
360
401
|
const [sheetOpen, setSheetOpen] = useState(false);
|
|
361
402
|
const [editingAccount, setEditingAccount] = useState<BankAccount | null>(
|
|
362
403
|
null
|
|
363
404
|
);
|
|
405
|
+
const [accountIdToDelete, setAccountIdToDelete] = useState<string | null>(
|
|
406
|
+
null
|
|
407
|
+
);
|
|
364
408
|
const { data: contasBancarias, refetch } = useQuery<BankAccount[]>({
|
|
365
|
-
queryKey: ['finance-bank-accounts'],
|
|
409
|
+
queryKey: ['finance-bank-accounts', currentLocaleCode],
|
|
366
410
|
queryFn: async () => {
|
|
367
411
|
const response = await request({
|
|
368
412
|
url: '/finance/bank-accounts',
|
|
@@ -371,8 +415,9 @@ export default function ContasBancariasPage() {
|
|
|
371
415
|
|
|
372
416
|
return (response.data || []) as BankAccount[];
|
|
373
417
|
},
|
|
374
|
-
|
|
418
|
+
placeholderData: [],
|
|
375
419
|
});
|
|
420
|
+
const accounts = contasBancarias ?? [];
|
|
376
421
|
|
|
377
422
|
const tipoConfig = {
|
|
378
423
|
corrente: { label: t('types.corrente'), icon: Building2 },
|
|
@@ -381,11 +426,11 @@ export default function ContasBancariasPage() {
|
|
|
381
426
|
caixa: { label: t('types.caixa'), icon: Wallet },
|
|
382
427
|
};
|
|
383
428
|
|
|
384
|
-
const saldoTotal =
|
|
429
|
+
const saldoTotal = accounts
|
|
385
430
|
.filter((c) => c.ativo)
|
|
386
431
|
.reduce((acc, c) => acc + c.saldoAtual, 0);
|
|
387
432
|
|
|
388
|
-
const saldoConciliadoTotal =
|
|
433
|
+
const saldoConciliadoTotal = accounts
|
|
389
434
|
.filter((c) => c.ativo)
|
|
390
435
|
.reduce((acc, c) => acc + c.saldoConciliado, 0);
|
|
391
436
|
|
|
@@ -399,25 +444,22 @@ export default function ContasBancariasPage() {
|
|
|
399
444
|
setSheetOpen(true);
|
|
400
445
|
};
|
|
401
446
|
|
|
402
|
-
const handleDelete = async (
|
|
403
|
-
|
|
404
|
-
'Deseja realmente inativar esta conta bancária?'
|
|
405
|
-
);
|
|
406
|
-
|
|
407
|
-
if (!confirmed) {
|
|
447
|
+
const handleDelete = async () => {
|
|
448
|
+
if (!accountIdToDelete) {
|
|
408
449
|
return;
|
|
409
450
|
}
|
|
410
451
|
|
|
411
452
|
try {
|
|
412
453
|
await request({
|
|
413
|
-
url: `/finance/bank-accounts/${
|
|
454
|
+
url: `/finance/bank-accounts/${accountIdToDelete}`,
|
|
414
455
|
method: 'DELETE',
|
|
415
456
|
});
|
|
416
457
|
|
|
417
458
|
await refetch();
|
|
418
|
-
showToastHandler?.('success',
|
|
459
|
+
showToastHandler?.('success', deleteSuccessMessage);
|
|
460
|
+
setAccountIdToDelete(null);
|
|
419
461
|
} catch {
|
|
420
|
-
showToastHandler?.('error',
|
|
462
|
+
showToastHandler?.('error', deleteErrorMessage);
|
|
421
463
|
}
|
|
422
464
|
};
|
|
423
465
|
|
|
@@ -448,6 +490,30 @@ export default function ContasBancariasPage() {
|
|
|
448
490
|
onEditingAccountChange={setEditingAccount}
|
|
449
491
|
/>
|
|
450
492
|
|
|
493
|
+
<AlertDialog
|
|
494
|
+
open={!!accountIdToDelete}
|
|
495
|
+
onOpenChange={(open) => {
|
|
496
|
+
if (!open) {
|
|
497
|
+
setAccountIdToDelete(null);
|
|
498
|
+
}
|
|
499
|
+
}}
|
|
500
|
+
>
|
|
501
|
+
<AlertDialogContent>
|
|
502
|
+
<AlertDialogHeader>
|
|
503
|
+
<AlertDialogTitle>{deleteDialogTitle}</AlertDialogTitle>
|
|
504
|
+
<AlertDialogDescription>
|
|
505
|
+
{deleteDialogDescription}
|
|
506
|
+
</AlertDialogDescription>
|
|
507
|
+
</AlertDialogHeader>
|
|
508
|
+
<AlertDialogFooter>
|
|
509
|
+
<AlertDialogCancel>{t('common.cancel')}</AlertDialogCancel>
|
|
510
|
+
<AlertDialogAction onClick={handleDelete}>
|
|
511
|
+
{deleteDialogConfirm}
|
|
512
|
+
</AlertDialogAction>
|
|
513
|
+
</AlertDialogFooter>
|
|
514
|
+
</AlertDialogContent>
|
|
515
|
+
</AlertDialog>
|
|
516
|
+
|
|
451
517
|
<div className="grid gap-4 md:grid-cols-2">
|
|
452
518
|
<Card>
|
|
453
519
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
@@ -462,7 +528,7 @@ export default function ContasBancariasPage() {
|
|
|
462
528
|
</div>
|
|
463
529
|
<p className="text-xs text-muted-foreground">
|
|
464
530
|
{t('cards.activeAccounts', {
|
|
465
|
-
count:
|
|
531
|
+
count: accounts.filter((c) => c.ativo).length,
|
|
466
532
|
})}
|
|
467
533
|
</p>
|
|
468
534
|
</CardContent>
|
|
@@ -487,7 +553,7 @@ export default function ContasBancariasPage() {
|
|
|
487
553
|
</div>
|
|
488
554
|
|
|
489
555
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
490
|
-
{
|
|
556
|
+
{accounts.map((conta) => {
|
|
491
557
|
const tipo =
|
|
492
558
|
tipoConfig[conta.tipo as keyof typeof tipoConfig] ||
|
|
493
559
|
tipoConfig.corrente;
|
|
@@ -503,14 +569,25 @@ export default function ContasBancariasPage() {
|
|
|
503
569
|
<TipoIcon className="h-5 w-5" />
|
|
504
570
|
</div>
|
|
505
571
|
<div>
|
|
506
|
-
<
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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', {
|
|
510
586
|
agency: conta.agencia,
|
|
511
587
|
account: conta.conta,
|
|
512
|
-
})
|
|
513
|
-
|
|
588
|
+
})}
|
|
589
|
+
</span>
|
|
590
|
+
)}
|
|
514
591
|
</CardDescription>
|
|
515
592
|
</div>
|
|
516
593
|
</div>
|
|
@@ -592,7 +669,7 @@ export default function ContasBancariasPage() {
|
|
|
592
669
|
<Button
|
|
593
670
|
variant="outline"
|
|
594
671
|
size="sm"
|
|
595
|
-
onClick={() =>
|
|
672
|
+
onClick={() => setAccountIdToDelete(conta.id)}
|
|
596
673
|
>
|
|
597
674
|
<Trash2 className="h-4 w-4" />
|
|
598
675
|
</Button>
|
|
@@ -446,8 +446,22 @@
|
|
|
446
446
|
"common": {
|
|
447
447
|
"select": "Select...",
|
|
448
448
|
"cancel": "Cancel",
|
|
449
|
+
"edit": "Edit",
|
|
449
450
|
"save": "Save"
|
|
450
451
|
},
|
|
452
|
+
"messages": {
|
|
453
|
+
"createSuccess": "Bank account created successfully",
|
|
454
|
+
"createError": "Failed to create bank account",
|
|
455
|
+
"updateSuccess": "Bank account updated successfully",
|
|
456
|
+
"updateError": "Failed to update bank account",
|
|
457
|
+
"deleteSuccess": "Bank account deactivated successfully",
|
|
458
|
+
"deleteError": "Failed to deactivate bank account"
|
|
459
|
+
},
|
|
460
|
+
"deleteDialog": {
|
|
461
|
+
"title": "Deactivate bank account",
|
|
462
|
+
"description": "Do you really want to deactivate this bank account?",
|
|
463
|
+
"confirm": "Deactivate"
|
|
464
|
+
},
|
|
451
465
|
"types": {
|
|
452
466
|
"corrente": "Checking Account",
|
|
453
467
|
"poupanca": "Savings Account",
|
|
@@ -446,8 +446,22 @@
|
|
|
446
446
|
"common": {
|
|
447
447
|
"select": "Selecione...",
|
|
448
448
|
"cancel": "Cancelar",
|
|
449
|
+
"edit": "Editar",
|
|
449
450
|
"save": "Salvar"
|
|
450
451
|
},
|
|
452
|
+
"messages": {
|
|
453
|
+
"createSuccess": "Conta bancária cadastrada com sucesso",
|
|
454
|
+
"createError": "Erro ao cadastrar conta bancária",
|
|
455
|
+
"updateSuccess": "Conta bancária atualizada com sucesso",
|
|
456
|
+
"updateError": "Erro ao atualizar conta bancária",
|
|
457
|
+
"deleteSuccess": "Conta bancária inativada com sucesso",
|
|
458
|
+
"deleteError": "Erro ao inativar conta bancária"
|
|
459
|
+
},
|
|
460
|
+
"deleteDialog": {
|
|
461
|
+
"title": "Inativar conta bancária",
|
|
462
|
+
"description": "Deseja realmente inativar esta conta bancária?",
|
|
463
|
+
"confirm": "Inativar"
|
|
464
|
+
},
|
|
451
465
|
"types": {
|
|
452
466
|
"corrente": "Conta Corrente",
|
|
453
467
|
"poupanca": "Poupança",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/finance",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.232",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
"@nestjs/core": "^11",
|
|
10
10
|
"@nestjs/jwt": "^11",
|
|
11
11
|
"@nestjs/mapped-types": "*",
|
|
12
|
-
"@hed-hog/api-prisma": "0.0.4",
|
|
13
12
|
"@hed-hog/api-locale": "0.0.11",
|
|
13
|
+
"@hed-hog/api-prisma": "0.0.4",
|
|
14
14
|
"@hed-hog/api-pagination": "0.0.5",
|
|
15
|
-
"@hed-hog/tag": "0.0.223",
|
|
16
|
-
"@hed-hog/api": "0.0.3",
|
|
17
15
|
"@hed-hog/api-types": "0.0.1",
|
|
18
|
-
"@hed-hog/
|
|
16
|
+
"@hed-hog/api": "0.0.3",
|
|
17
|
+
"@hed-hog/tag": "0.0.232",
|
|
18
|
+
"@hed-hog/contact": "0.0.232"
|
|
19
19
|
},
|
|
20
20
|
"exports": {
|
|
21
21
|
".": {
|
|
@@ -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
|
}
|