@hed-hog/contact 0.0.347 → 0.0.350
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/contact.service.d.ts +2 -2
- package/dist/person/dto/account.dto.d.ts +2 -0
- package/dist/person/dto/account.dto.d.ts.map +1 -1
- package/dist/person/dto/account.dto.js +10 -0
- package/dist/person/dto/account.dto.js.map +1 -1
- package/dist/person/person.controller.d.ts +7 -5
- package/dist/person/person.controller.d.ts.map +1 -1
- package/dist/person/person.service.d.ts +3 -0
- package/dist/person/person.service.d.ts.map +1 -1
- package/dist/person/person.service.js +16 -0
- package/dist/person/person.service.js.map +1 -1
- package/hedhog/frontend/app/accounts/_components/account-form-sheet.tsx.ejs +110 -28
- package/hedhog/frontend/app/accounts/_components/account-types.ts.ejs +4 -0
- package/hedhog/frontend/app/accounts/page.tsx.ejs +2 -0
- package/hedhog/frontend/app/person/_components/person-form-sheet.tsx.ejs +95 -75
- package/hedhog/frontend/app/person/_components/person-interaction-dialog.tsx.ejs +156 -150
- package/hedhog/frontend/app/proposals/_components/proposals-management-page.tsx.ejs +20 -2
- package/hedhog/frontend/messages/pt.json +2 -2
- package/package.json +5 -5
- package/src/person/dto/account.dto.ts +9 -0
- package/src/person/person.service.ts +40 -21
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { Button } from '@/components/ui/button';
|
|
4
|
-
import {
|
|
5
|
-
Dialog,
|
|
6
|
-
DialogContent,
|
|
7
|
-
DialogDescription,
|
|
8
|
-
DialogFooter,
|
|
9
|
-
DialogHeader,
|
|
10
|
-
DialogTitle,
|
|
11
|
-
} from '@/components/ui/dialog';
|
|
12
4
|
import {
|
|
13
5
|
Form,
|
|
14
6
|
FormControl,
|
|
@@ -25,6 +17,14 @@ import {
|
|
|
25
17
|
SelectTrigger,
|
|
26
18
|
SelectValue,
|
|
27
19
|
} from '@/components/ui/select';
|
|
20
|
+
import {
|
|
21
|
+
Sheet,
|
|
22
|
+
SheetContent,
|
|
23
|
+
SheetDescription,
|
|
24
|
+
SheetFooter,
|
|
25
|
+
SheetHeader,
|
|
26
|
+
SheetTitle,
|
|
27
|
+
} from '@/components/ui/sheet';
|
|
28
28
|
import { Textarea } from '@/components/ui/textarea';
|
|
29
29
|
import { useFormDraft } from '@/hooks/use-form-draft';
|
|
30
30
|
import { formatDateTime } from '@/lib/format-date';
|
|
@@ -290,152 +290,158 @@ export function PersonInteractionDialog({
|
|
|
290
290
|
};
|
|
291
291
|
|
|
292
292
|
return (
|
|
293
|
-
<
|
|
294
|
-
<
|
|
295
|
-
|
|
296
|
-
|
|
293
|
+
<Sheet open={open} onOpenChange={onOpenChange}>
|
|
294
|
+
<SheetContent
|
|
295
|
+
side="right"
|
|
296
|
+
className="flex h-full w-full flex-col gap-0 overflow-hidden p-0 sm:max-w-lg"
|
|
297
|
+
>
|
|
298
|
+
<SheetHeader className="shrink-0 border-b px-6 py-4 text-left">
|
|
299
|
+
<SheetTitle>
|
|
297
300
|
{mode === 'interaction'
|
|
298
301
|
? t('registerInteraction')
|
|
299
302
|
: t('scheduleFollowup')}
|
|
300
|
-
</
|
|
301
|
-
{person ? <
|
|
302
|
-
</
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
<
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
<
|
|
316
|
-
|
|
303
|
+
</SheetTitle>
|
|
304
|
+
{person ? <SheetDescription>{person.name}</SheetDescription> : null}
|
|
305
|
+
</SheetHeader>
|
|
306
|
+
|
|
307
|
+
<div className="flex-1 overflow-y-auto px-6 py-4">
|
|
308
|
+
{mode === 'interaction' ? (
|
|
309
|
+
<Form {...interactionForm}>
|
|
310
|
+
<form
|
|
311
|
+
onSubmit={interactionForm.handleSubmit(handleInteractionSubmit)}
|
|
312
|
+
className="space-y-4"
|
|
313
|
+
>
|
|
314
|
+
<FormField
|
|
315
|
+
control={interactionForm.control}
|
|
316
|
+
name="type"
|
|
317
|
+
render={({ field }) => (
|
|
318
|
+
<FormItem className="min-w-0">
|
|
319
|
+
<FormLabel>{t('interactionType')}</FormLabel>
|
|
320
|
+
<Select
|
|
321
|
+
onValueChange={field.onChange}
|
|
322
|
+
value={field.value}
|
|
323
|
+
>
|
|
324
|
+
<FormControl>
|
|
325
|
+
<SelectTrigger className="h-9 w-full min-w-0">
|
|
326
|
+
<SelectValue />
|
|
327
|
+
</SelectTrigger>
|
|
328
|
+
</FormControl>
|
|
329
|
+
<SelectContent
|
|
330
|
+
position="popper"
|
|
331
|
+
className="w-[--radix-select-trigger-width] min-w-(--radix-select-trigger-width)"
|
|
332
|
+
>
|
|
333
|
+
{INTERACTION_TYPES.map((type) => (
|
|
334
|
+
<SelectItem key={type} value={type}>
|
|
335
|
+
{t(
|
|
336
|
+
`interactionType_${type}` as Parameters<
|
|
337
|
+
typeof t
|
|
338
|
+
>[0]
|
|
339
|
+
)}
|
|
340
|
+
</SelectItem>
|
|
341
|
+
))}
|
|
342
|
+
</SelectContent>
|
|
343
|
+
</Select>
|
|
344
|
+
<FormMessage />
|
|
345
|
+
</FormItem>
|
|
346
|
+
)}
|
|
347
|
+
/>
|
|
348
|
+
<FormField
|
|
349
|
+
control={interactionForm.control}
|
|
350
|
+
name="notes"
|
|
351
|
+
render={({ field }) => (
|
|
352
|
+
<FormItem>
|
|
353
|
+
<FormLabel>{t('notes')}</FormLabel>
|
|
354
|
+
<FormControl>
|
|
355
|
+
<Textarea
|
|
356
|
+
{...field}
|
|
357
|
+
placeholder={t('notesPlaceholder')}
|
|
358
|
+
rows={4}
|
|
359
|
+
/>
|
|
360
|
+
</FormControl>
|
|
361
|
+
<FormMessage />
|
|
362
|
+
</FormItem>
|
|
363
|
+
)}
|
|
364
|
+
/>
|
|
365
|
+
{interactionDraftStatus ? (
|
|
366
|
+
<p className="text-xs text-muted-foreground">
|
|
367
|
+
{interactionDraftStatus}
|
|
368
|
+
</p>
|
|
369
|
+
) : null}
|
|
370
|
+
</form>
|
|
371
|
+
</Form>
|
|
372
|
+
) : (
|
|
373
|
+
<Form {...followupForm}>
|
|
374
|
+
<form
|
|
375
|
+
onSubmit={followupForm.handleSubmit(handleFollowupSubmit)}
|
|
376
|
+
className="space-y-4"
|
|
377
|
+
>
|
|
378
|
+
<FormField
|
|
379
|
+
control={followupForm.control}
|
|
380
|
+
name="next_action_at"
|
|
381
|
+
render={({ field }) => (
|
|
382
|
+
<FormItem>
|
|
383
|
+
<FormLabel>{t('followupDate')}</FormLabel>
|
|
384
|
+
<FormControl>
|
|
385
|
+
<Input type="datetime-local" {...field} />
|
|
386
|
+
</FormControl>
|
|
387
|
+
<FormMessage />
|
|
388
|
+
</FormItem>
|
|
389
|
+
)}
|
|
390
|
+
/>
|
|
391
|
+
<FormField
|
|
392
|
+
control={followupForm.control}
|
|
393
|
+
name="notes"
|
|
394
|
+
render={({ field }) => (
|
|
395
|
+
<FormItem>
|
|
396
|
+
<FormLabel>{t('notes')}</FormLabel>
|
|
317
397
|
<FormControl>
|
|
318
|
-
<
|
|
319
|
-
|
|
320
|
-
|
|
398
|
+
<Textarea
|
|
399
|
+
{...field}
|
|
400
|
+
placeholder={t('notesPlaceholder')}
|
|
401
|
+
rows={4}
|
|
402
|
+
/>
|
|
321
403
|
</FormControl>
|
|
322
|
-
<
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
onClick={() => onOpenChange(false)}
|
|
365
|
-
disabled={isSubmitting}
|
|
366
|
-
>
|
|
367
|
-
{t('cancel')}
|
|
368
|
-
</Button>
|
|
369
|
-
<Button type="submit" disabled={isSubmitting}>
|
|
370
|
-
{isSubmitting ? (
|
|
371
|
-
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
372
|
-
) : null}
|
|
373
|
-
{t('register')}
|
|
374
|
-
</Button>
|
|
375
|
-
</DialogFooter>
|
|
376
|
-
</form>
|
|
377
|
-
</Form>
|
|
378
|
-
) : (
|
|
379
|
-
<Form {...followupForm}>
|
|
380
|
-
<form
|
|
381
|
-
onSubmit={followupForm.handleSubmit(handleFollowupSubmit)}
|
|
382
|
-
className="space-y-4"
|
|
383
|
-
>
|
|
384
|
-
<FormField
|
|
385
|
-
control={followupForm.control}
|
|
386
|
-
name="next_action_at"
|
|
387
|
-
render={({ field }) => (
|
|
388
|
-
<FormItem>
|
|
389
|
-
<FormLabel>{t('followupDate')}</FormLabel>
|
|
390
|
-
<FormControl>
|
|
391
|
-
<Input type="datetime-local" {...field} />
|
|
392
|
-
</FormControl>
|
|
393
|
-
<FormMessage />
|
|
394
|
-
</FormItem>
|
|
395
|
-
)}
|
|
396
|
-
/>
|
|
397
|
-
<FormField
|
|
398
|
-
control={followupForm.control}
|
|
399
|
-
name="notes"
|
|
400
|
-
render={({ field }) => (
|
|
401
|
-
<FormItem>
|
|
402
|
-
<FormLabel>{t('notes')}</FormLabel>
|
|
403
|
-
<FormControl>
|
|
404
|
-
<Textarea
|
|
405
|
-
{...field}
|
|
406
|
-
placeholder={t('notesPlaceholder')}
|
|
407
|
-
rows={4}
|
|
408
|
-
/>
|
|
409
|
-
</FormControl>
|
|
410
|
-
<FormMessage />
|
|
411
|
-
</FormItem>
|
|
412
|
-
)}
|
|
413
|
-
/>
|
|
414
|
-
{followupDraftStatus ? (
|
|
415
|
-
<p className="text-xs text-muted-foreground">
|
|
416
|
-
{followupDraftStatus}
|
|
417
|
-
</p>
|
|
418
|
-
) : null}
|
|
419
|
-
<DialogFooter>
|
|
420
|
-
<Button
|
|
421
|
-
type="button"
|
|
422
|
-
variant="outline"
|
|
423
|
-
onClick={() => onOpenChange(false)}
|
|
424
|
-
disabled={isSubmitting}
|
|
425
|
-
>
|
|
426
|
-
{t('cancel')}
|
|
427
|
-
</Button>
|
|
428
|
-
<Button type="submit" disabled={isSubmitting}>
|
|
429
|
-
{isSubmitting ? (
|
|
430
|
-
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
431
|
-
) : null}
|
|
432
|
-
{t('save')}
|
|
433
|
-
</Button>
|
|
434
|
-
</DialogFooter>
|
|
435
|
-
</form>
|
|
436
|
-
</Form>
|
|
437
|
-
)}
|
|
438
|
-
</DialogContent>
|
|
439
|
-
</Dialog>
|
|
404
|
+
<FormMessage />
|
|
405
|
+
</FormItem>
|
|
406
|
+
)}
|
|
407
|
+
/>
|
|
408
|
+
{followupDraftStatus ? (
|
|
409
|
+
<p className="text-xs text-muted-foreground">
|
|
410
|
+
{followupDraftStatus}
|
|
411
|
+
</p>
|
|
412
|
+
) : null}
|
|
413
|
+
</form>
|
|
414
|
+
</Form>
|
|
415
|
+
)}
|
|
416
|
+
</div>
|
|
417
|
+
|
|
418
|
+
<SheetFooter className="shrink-0 border-t px-6 py-3 sm:justify-end">
|
|
419
|
+
<Button
|
|
420
|
+
type="button"
|
|
421
|
+
variant="outline"
|
|
422
|
+
onClick={() => onOpenChange(false)}
|
|
423
|
+
disabled={isSubmitting}
|
|
424
|
+
>
|
|
425
|
+
{t('cancel')}
|
|
426
|
+
</Button>
|
|
427
|
+
<Button
|
|
428
|
+
type="button"
|
|
429
|
+
disabled={isSubmitting}
|
|
430
|
+
onClick={() => {
|
|
431
|
+
if (mode === 'interaction') {
|
|
432
|
+
void interactionForm.handleSubmit(handleInteractionSubmit)();
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
void followupForm.handleSubmit(handleFollowupSubmit)();
|
|
436
|
+
}}
|
|
437
|
+
>
|
|
438
|
+
{isSubmitting ? (
|
|
439
|
+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
440
|
+
) : null}
|
|
441
|
+
{mode === 'interaction' ? t('register') : t('save')}
|
|
442
|
+
</Button>
|
|
443
|
+
</SheetFooter>
|
|
444
|
+
</SheetContent>
|
|
445
|
+
</Sheet>
|
|
440
446
|
);
|
|
441
447
|
}
|
|
@@ -604,9 +604,19 @@ export function ProposalsManagementPage({
|
|
|
604
604
|
proposal.person?.trade_name ||
|
|
605
605
|
proposal.person?.name ||
|
|
606
606
|
`#${proposal.person_id}`;
|
|
607
|
+
const editable = canEditProposal(proposal.status);
|
|
607
608
|
|
|
608
609
|
return (
|
|
609
|
-
<TableRow
|
|
610
|
+
<TableRow
|
|
611
|
+
key={proposal.id}
|
|
612
|
+
onDoubleClick={() => {
|
|
613
|
+
if (!editable) return;
|
|
614
|
+
handleEdit(proposal);
|
|
615
|
+
}}
|
|
616
|
+
className={cn(
|
|
617
|
+
editable && 'cursor-pointer hover:bg-muted/20'
|
|
618
|
+
)}
|
|
619
|
+
>
|
|
610
620
|
<TableCell>
|
|
611
621
|
<div className="space-y-1">
|
|
612
622
|
<div className="font-medium text-foreground">
|
|
@@ -776,11 +786,19 @@ export function ProposalsManagementPage({
|
|
|
776
786
|
proposal.person?.trade_name ||
|
|
777
787
|
proposal.person?.name ||
|
|
778
788
|
`#${proposal.person_id}`;
|
|
789
|
+
const editable = canEditProposal(proposal.status);
|
|
779
790
|
|
|
780
791
|
return (
|
|
781
792
|
<Card
|
|
782
793
|
key={proposal.id}
|
|
783
|
-
|
|
794
|
+
onDoubleClick={() => {
|
|
795
|
+
if (!editable) return;
|
|
796
|
+
handleEdit(proposal);
|
|
797
|
+
}}
|
|
798
|
+
className={cn(
|
|
799
|
+
'h-full overflow-hidden border-border/70 py-0',
|
|
800
|
+
editable && 'cursor-pointer'
|
|
801
|
+
)}
|
|
784
802
|
>
|
|
785
803
|
<CardContent className="flex h-full flex-col gap-3 p-4">
|
|
786
804
|
<div className="flex items-start justify-between gap-3">
|
|
@@ -117,8 +117,8 @@
|
|
|
117
117
|
"selectType": "Selecione o tipo",
|
|
118
118
|
"birthDate": "Data de Nascimento",
|
|
119
119
|
"selectDate": "Selecionar data",
|
|
120
|
-
"gender": "
|
|
121
|
-
"selectGender": "Selecione o
|
|
120
|
+
"gender": "Gênero",
|
|
121
|
+
"selectGender": "Selecione o gênero",
|
|
122
122
|
"genderMale": "Masculino",
|
|
123
123
|
"genderFemale": "Feminino",
|
|
124
124
|
"genderOther": "Outro",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/contact",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.350",
|
|
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
|
"playwright": "^1.49.0",
|
|
13
|
-
"@hed-hog/address": "0.0.347",
|
|
14
|
-
"@hed-hog/core": "0.0.347",
|
|
15
13
|
"@hed-hog/api": "0.0.8",
|
|
16
|
-
"@hed-hog/
|
|
14
|
+
"@hed-hog/address": "0.0.350",
|
|
17
15
|
"@hed-hog/api-pagination": "0.0.7",
|
|
18
16
|
"@hed-hog/api-mail": "0.0.9",
|
|
19
|
-
"@hed-hog/api-
|
|
17
|
+
"@hed-hog/api-prisma": "0.0.6",
|
|
18
|
+
"@hed-hog/api-locale": "0.0.14",
|
|
19
|
+
"@hed-hog/core": "0.0.350"
|
|
20
20
|
},
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from 'class-transformer';
|
|
2
2
|
import {
|
|
3
3
|
IsArray,
|
|
4
|
+
IsDateString,
|
|
4
5
|
IsEmail,
|
|
5
6
|
IsIn,
|
|
6
7
|
IsInt,
|
|
@@ -56,6 +57,14 @@ export class CreateAccountDTO {
|
|
|
56
57
|
@IsString()
|
|
57
58
|
trade_name?: string | null;
|
|
58
59
|
|
|
60
|
+
@IsOptional()
|
|
61
|
+
@IsDateString()
|
|
62
|
+
foundation_date?: string | null;
|
|
63
|
+
|
|
64
|
+
@IsOptional()
|
|
65
|
+
@IsString()
|
|
66
|
+
legal_nature?: string | null;
|
|
67
|
+
|
|
59
68
|
@IsIn([PersonStatus.ACTIVE, PersonStatus.INACTIVE])
|
|
60
69
|
status: PersonStatus;
|
|
61
70
|
|
|
@@ -4,40 +4,40 @@ import { PaginationDTO, PaginationService } from '@hed-hog/api-pagination';
|
|
|
4
4
|
import { Prisma, PrismaService } from '@hed-hog/api-prisma';
|
|
5
5
|
import { FileService, IntegrationDeveloperApiService, SettingService } from '@hed-hog/core';
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
BadRequestException,
|
|
8
|
+
Inject,
|
|
9
|
+
Injectable,
|
|
10
|
+
Logger,
|
|
11
|
+
NotFoundException,
|
|
12
|
+
forwardRef,
|
|
13
13
|
} from '@nestjs/common';
|
|
14
14
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
ACCOUNT_LIFECYCLE_STAGES,
|
|
16
|
+
type AccountLifecycleStage,
|
|
17
|
+
type CreateAccountDTO,
|
|
18
|
+
type UpdateAccountDTO,
|
|
19
19
|
} from './dto/account.dto';
|
|
20
20
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
type ActivityListQueryDTO,
|
|
22
|
+
type CrmActivityPriority,
|
|
23
|
+
type CrmActivitySourceKind,
|
|
24
|
+
type CrmActivityStatus,
|
|
25
|
+
type CrmActivityType,
|
|
26
26
|
} from './dto/activity.dto';
|
|
27
27
|
import { CreateFollowupDTO } from './dto/create-followup.dto';
|
|
28
28
|
import {
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
CreateInteractionDTO,
|
|
30
|
+
PersonInteractionTypeDTO,
|
|
31
31
|
} from './dto/create-interaction.dto';
|
|
32
32
|
import { CreateDTO } from './dto/create.dto';
|
|
33
33
|
import {
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
type CrmDashboardPeriod,
|
|
35
|
+
type DashboardQueryDTO,
|
|
36
36
|
} from './dto/dashboard-query.dto';
|
|
37
37
|
import { CheckPersonDuplicatesQueryDTO } from './dto/duplicates-query.dto';
|
|
38
38
|
import {
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
FollowupListQueryDTO,
|
|
40
|
+
FollowupStatsQueryDTO,
|
|
41
41
|
} from './dto/followup-query.dto';
|
|
42
42
|
import { CRM_IMPORT_FIELDS } from './dto/import.dto';
|
|
43
43
|
import { MergePersonDTO } from './dto/merge.dto';
|
|
@@ -117,6 +117,8 @@ type AccountListItem = {
|
|
|
117
117
|
id: number;
|
|
118
118
|
name: string;
|
|
119
119
|
trade_name: string | null;
|
|
120
|
+
foundation_date: string | null;
|
|
121
|
+
legal_nature: string | null;
|
|
120
122
|
status: 'active' | 'inactive';
|
|
121
123
|
industry: string | null;
|
|
122
124
|
website: string | null;
|
|
@@ -4326,6 +4328,21 @@ export class PersonService {
|
|
|
4326
4328
|
return Number.isNaN(date.getTime()) ? null : date.toISOString();
|
|
4327
4329
|
}
|
|
4328
4330
|
|
|
4331
|
+
private normalizeDateOrNull(value: unknown): string | null {
|
|
4332
|
+
if (!value) return null;
|
|
4333
|
+
|
|
4334
|
+
if (value instanceof Date) {
|
|
4335
|
+
return Number.isNaN(value.getTime()) ? null : value.toISOString().slice(0, 10);
|
|
4336
|
+
}
|
|
4337
|
+
|
|
4338
|
+
const normalized = this.normalizeTextOrNull(value);
|
|
4339
|
+
if (!normalized) return null;
|
|
4340
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(normalized)) return normalized;
|
|
4341
|
+
|
|
4342
|
+
const date = new Date(normalized);
|
|
4343
|
+
return Number.isNaN(date.getTime()) ? null : date.toISOString().slice(0, 10);
|
|
4344
|
+
}
|
|
4345
|
+
|
|
4329
4346
|
private coerceNumber(value: unknown): number {
|
|
4330
4347
|
const parsed = Number(value);
|
|
4331
4348
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
@@ -4622,6 +4639,8 @@ export class PersonService {
|
|
|
4622
4639
|
id: person.id,
|
|
4623
4640
|
name: person.name,
|
|
4624
4641
|
trade_name: company.trade_name ?? null,
|
|
4642
|
+
foundation_date: this.normalizeDateOrNull(company.foundation_date),
|
|
4643
|
+
legal_nature: this.normalizeTextOrNull(company.legal_nature),
|
|
4625
4644
|
status: person.status,
|
|
4626
4645
|
industry: company.industry ?? null,
|
|
4627
4646
|
website: company.website ?? null,
|