evo360-types 1.3.574 → 1.3.581
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/apps/evo-chat/channel/zod-schemas.d.ts +273 -0
- package/dist/apps/evo-chat/channel/zod-schemas.js +17 -1
- package/dist/apps/evo-chat/channel/zod-schemas.ts +19 -0
- package/dist/apps/evo-chat/thread-message/zod-schemas.d.ts +24 -0
- package/dist/apps/evo-chat/thread-message/zod-schemas.js +2 -0
- package/dist/apps/evo-chat/thread-message/zod-schemas.ts +2 -0
- package/dist/apps/evo-chat/waba-template/zod-schemas.d.ts +6 -0
- package/dist/apps/evo-chat/waba-template/zod-schemas.js +2 -0
- package/dist/apps/evo-chat/waba-template/zod-schemas.ts +2 -0
- package/dist/apps/evo-crm/lead/zod-schemas.d.ts +9 -0
- package/dist/apps/evo-med/calendar/zod-schemas.d.ts +4215 -1256
- package/dist/apps/evo-med/calendar/zod-schemas.js +61 -1
- package/dist/apps/evo-med/calendar/zod-schemas.ts +64 -0
- package/dist/apps/evo-med/insurance/zod-schemas.d.ts +9 -0
- package/dist/apps/evo-med/people/zod-schemas.d.ts +18 -0
- package/dist/apps/evo-notifications/zod-schemas.d.ts +110 -0
- package/dist/apps/evo-notifications/zod-schemas.js +8 -1
- package/dist/apps/evo-notifications/zod-schemas.ts +9 -0
- package/dist/apps/evo-telemedicine/zod-schemas.d.ts +161 -13
- package/dist/apps/evo-telemedicine/zod-schemas.js +93 -2
- package/dist/apps/evo-telemedicine/zod-schemas.ts +96 -0
- package/dist/apps/shared/zod-schemas.d.ts +3 -0
- package/dist/apps/shared/zod-schemas.js +2 -0
- package/dist/apps/shared/zod-schemas.ts +2 -0
- package/dist/types/evo-chat/channel/index.d.ts +19 -0
- package/dist/types/evo-chat/channel/index.ts +24 -0
- package/dist/types/evo-chat/thread-message/index.d.ts +4 -0
- package/dist/types/evo-chat/thread-message/index.ts +4 -0
- package/dist/types/evo-chat/waba-template/index.d.ts +6 -0
- package/dist/types/evo-chat/waba-template/index.js +3 -1
- package/dist/types/evo-chat/waba-template/index.ts +7 -0
- package/dist/types/evo-finops/common/contract.d.ts +8 -0
- package/dist/types/evo-finops/common/contract.js +7 -0
- package/dist/types/evo-finops/common/contract.ts +7 -0
- package/dist/types/evo-med/calendar/index.d.ts +124 -1
- package/dist/types/evo-med/calendar/index.js +60 -1
- package/dist/types/evo-med/calendar/index.ts +167 -1
- package/dist/types/evo-notifications/index.d.ts +11 -0
- package/dist/types/evo-notifications/index.ts +13 -0
- package/dist/types/evo-reports/index.d.ts +27 -0
- package/dist/types/evo-reports/index.ts +28 -0
- package/dist/types/evo-telemedicine/index.d.ts +421 -6
- package/dist/types/evo-telemedicine/index.js +69 -1
- package/dist/types/evo-telemedicine/index.ts +454 -6
- package/dist/types/shared/index.d.ts +1 -0
- package/dist/types/shared/index.ts +2 -0
- package/package.json +1 -1
|
@@ -112,6 +112,9 @@ export const zArtifactTypeSchema = z.enum([
|
|
|
112
112
|
"transcript",
|
|
113
113
|
]);
|
|
114
114
|
|
|
115
|
+
/** Espelha `ArtifactDispositionEnum` (feat-160 F21). */
|
|
116
|
+
export const zArtifactDispositionSchema = z.enum(["inline", "attachment"]);
|
|
117
|
+
|
|
115
118
|
/** Espelha `ArtifactStatusEnum`. */
|
|
116
119
|
export const zArtifactStatusSchema = z.enum([
|
|
117
120
|
"pending",
|
|
@@ -127,6 +130,8 @@ export const zAccessGrantKindSchema = z.enum([
|
|
|
127
130
|
"qr_capability",
|
|
128
131
|
"launch_code",
|
|
129
132
|
"browser_session",
|
|
133
|
+
// feat-160 F7: `kind` de uma ENTRADA do `grant-index`, nunca de um grant.
|
|
134
|
+
"ics_capability",
|
|
130
135
|
]);
|
|
131
136
|
|
|
132
137
|
/** Espelha `AccessGrantStateEnum`. */
|
|
@@ -173,6 +178,7 @@ export const zTeleconsultationEventTypeSchema = z.enum([
|
|
|
173
178
|
"teleconsultation.expired",
|
|
174
179
|
"teleconsultation.diverged",
|
|
175
180
|
"access.created",
|
|
181
|
+
"access.link_revealed",
|
|
176
182
|
"access.revoked",
|
|
177
183
|
"access.exchanged",
|
|
178
184
|
"access.verification_failed",
|
|
@@ -196,8 +202,10 @@ export const zTeleconsultationEventTypeSchema = z.enum([
|
|
|
196
202
|
"recording.consent_requested",
|
|
197
203
|
"recording.consent_accepted",
|
|
198
204
|
"recording.consent_declined",
|
|
205
|
+
"recording.consent_declined_pre_join",
|
|
199
206
|
"recording.consent_withdrawn",
|
|
200
207
|
"recording.started",
|
|
208
|
+
"recording.auto_started",
|
|
201
209
|
"recording.stopped",
|
|
202
210
|
"recording.failed",
|
|
203
211
|
"transcription.queued",
|
|
@@ -207,6 +215,7 @@ export const zTeleconsultationEventTypeSchema = z.enum([
|
|
|
207
215
|
"consultation.started",
|
|
208
216
|
"consultation.reconnecting",
|
|
209
217
|
"consultation.ended",
|
|
218
|
+
"teleconsultation.usage_skipped",
|
|
210
219
|
"artifact.accessed",
|
|
211
220
|
"artifact.deleted",
|
|
212
221
|
"entitlement.denied",
|
|
@@ -325,7 +334,17 @@ export const zTeleconsultationSchema = zFireDocSchema
|
|
|
325
334
|
provider_meeting_id: z.string().optional(),
|
|
326
335
|
active_provider_session_id: z.string().optional(),
|
|
327
336
|
recording_status: zRecordingStatusSchema,
|
|
337
|
+
recording_request_id: z.string().optional(),
|
|
338
|
+
recording_terms_version: z.string().optional(),
|
|
339
|
+
recording_requested_at: zDateNullable,
|
|
340
|
+
recording_requested_by: z.string().optional(),
|
|
341
|
+
recording_started_at: zDateNullable,
|
|
342
|
+
recording_stopped_at: zDateNullable,
|
|
343
|
+
recording_failure_code: z.string().nullable().optional(),
|
|
344
|
+
recording_segment: z.number().int().min(0).optional(),
|
|
328
345
|
transcription_status: zTranscriptionStatusSchema,
|
|
346
|
+
provider_teardown_pending: z.boolean().optional(),
|
|
347
|
+
metadata_retention_until: zDateNullable,
|
|
329
348
|
entitlement_snapshot: zTeleconsultationEntitlementSnapshotSchema,
|
|
330
349
|
generation: z.number().int().min(0),
|
|
331
350
|
reschedule_count: z.number().int().min(0).optional(),
|
|
@@ -334,10 +353,34 @@ export const zTeleconsultationSchema = zFireDocSchema
|
|
|
334
353
|
.nullable()
|
|
335
354
|
.optional(),
|
|
336
355
|
last_reconciled_at: zDateNullable,
|
|
356
|
+
usage_metering_due_at: zDateNullable,
|
|
357
|
+
usage_metered_at: zDateNullable,
|
|
337
358
|
version: z.number().int().min(0),
|
|
338
359
|
})
|
|
339
360
|
.passthrough();
|
|
340
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Espelha `ITeleconsultationPrivateProvider` (subdoc `private/provider`).
|
|
364
|
+
*
|
|
365
|
+
* NÃO estende `zFireDocSchema`: o subdoc não é um IFireDoc (não tem `version`
|
|
366
|
+
* de concorrência nem `ref`), e é lido sempre pelo backend com `id` do snap.
|
|
367
|
+
*/
|
|
368
|
+
export const zTeleconsultationPrivateProviderSchema = z
|
|
369
|
+
.object({
|
|
370
|
+
id: z.string(),
|
|
371
|
+
tenant: z.string().min(1),
|
|
372
|
+
teleconsultation_id: z.string().min(1),
|
|
373
|
+
provider: zTeleconsultationProviderSchema,
|
|
374
|
+
provider_meeting_id: z.string().optional(),
|
|
375
|
+
active_provider_session_id: z.string().optional(),
|
|
376
|
+
provider_session_ids: z.array(z.string().min(1)).optional(),
|
|
377
|
+
provider_participant_ids: z.record(z.string(), z.string()).optional(),
|
|
378
|
+
active_provider_recording_id: z.string().nullable().optional(),
|
|
379
|
+
created_at: zDateNullable,
|
|
380
|
+
updated_at: zDateNullable,
|
|
381
|
+
})
|
|
382
|
+
.passthrough();
|
|
383
|
+
|
|
341
384
|
/** Espelha `ITeleconsultationParticipant`. */
|
|
342
385
|
export const zTeleconsultationParticipantSchema = zFireDocSchema
|
|
343
386
|
.extend({
|
|
@@ -399,6 +442,7 @@ export const zTeleconsultationArtifactSchema = zFireDocSchema
|
|
|
399
442
|
started_at: zDateNullable,
|
|
400
443
|
ended_at: zDateNullable,
|
|
401
444
|
expires_at: zDateNullable,
|
|
445
|
+
deleted_at: zDateNullable,
|
|
402
446
|
error_code: z.string().optional(),
|
|
403
447
|
})
|
|
404
448
|
.passthrough();
|
|
@@ -486,6 +530,8 @@ export const zTelemedicineAppointmentIndexSchema = zFireDocSchema
|
|
|
486
530
|
.union([z.number(), z.string()])
|
|
487
531
|
.nullable()
|
|
488
532
|
.optional(),
|
|
533
|
+
last_reconciled_at: zDateNullable,
|
|
534
|
+
last_teleconsultation_id: z.string().nullable().optional(),
|
|
489
535
|
})
|
|
490
536
|
.passthrough();
|
|
491
537
|
|
|
@@ -569,6 +615,7 @@ export const zTelemedicineGrantIndexSchema = zGlobalDocSchema
|
|
|
569
615
|
tenant: z.string().min(1),
|
|
570
616
|
teleconsultation_id: z.string().min(1),
|
|
571
617
|
grant_id: z.string().min(1),
|
|
618
|
+
kind: zAccessGrantKindSchema.optional(),
|
|
572
619
|
expires_at: zDate,
|
|
573
620
|
})
|
|
574
621
|
.passthrough();
|
|
@@ -654,6 +701,36 @@ export const zConsentCommandSchema = z
|
|
|
654
701
|
})
|
|
655
702
|
.strict();
|
|
656
703
|
|
|
704
|
+
/**
|
|
705
|
+
* `POST /api/room/v1/join` — espelha `IJoinCommand`.
|
|
706
|
+
*
|
|
707
|
+
* `.passthrough()`, não `.strict()`, ao contrário dos outros comandos: o
|
|
708
|
+
* backend hoje LÊ os dois booleanos à mão e ignora o resto, e o corpo é a
|
|
709
|
+
* intenção de mídia do preflight. Trocar por `.strict()` faria um campo novo do
|
|
710
|
+
* SPA derrubar o join inteiro em `400` — alto preço para um corpo que o
|
|
711
|
+
* servidor pode ignorar por completo.
|
|
712
|
+
*/
|
|
713
|
+
export const zJoinCommandSchema = z
|
|
714
|
+
.object({
|
|
715
|
+
audio: z.boolean().optional(),
|
|
716
|
+
video: z.boolean().optional(),
|
|
717
|
+
})
|
|
718
|
+
.passthrough();
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* `POST /api/room/v1/leave` — espelha `ILeaveCommand`.
|
|
722
|
+
*
|
|
723
|
+
* `.passthrough()` pelo mesmo motivo, agravado: este corpo chega pelo
|
|
724
|
+
* `pagehide` com `fetch(keepalive)` e é a ÚLTIMA chance de registrar a saída.
|
|
725
|
+
* Um 400 aqui é uma saída perdida, e o backend já trata corpo ausente
|
|
726
|
+
* (`reason` default `'temporary'`).
|
|
727
|
+
*/
|
|
728
|
+
export const zLeaveCommandSchema = z
|
|
729
|
+
.object({
|
|
730
|
+
reason: z.string().trim().min(1).max(60).optional(),
|
|
731
|
+
})
|
|
732
|
+
.passthrough();
|
|
733
|
+
|
|
657
734
|
/** `POST /api/room/v1/presence` — espelha `IPresenceCommand`. */
|
|
658
735
|
export const zPresenceCommandSchema = z
|
|
659
736
|
.object({
|
|
@@ -721,3 +798,22 @@ export const zTelemetryCommandSchema = z
|
|
|
721
798
|
.max(50),
|
|
722
799
|
})
|
|
723
800
|
.strict();
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* `POST /v1/teleconsultations/:id/artifacts/:artifactId/signed-url` (feat-160
|
|
804
|
+
* F21) — espelha `IArtifactSignedUrlCommand`.
|
|
805
|
+
*
|
|
806
|
+
* `.strict()` de propósito: chave desconhecida aqui é erro de contrato —
|
|
807
|
+
* `ttlSeconds` em camelCase passaria em silêncio como "sem TTL pedido" e o bug
|
|
808
|
+
* apareceria como "o teto não respeita o que eu mandei". 30 s é o piso do use
|
|
809
|
+
* case e 900 s (`ARTIFACT_INLINE_SIGNED_URL_MAX_SECONDS`) o teto do modo mais
|
|
810
|
+
* generoso; o teto REAL por modo é aplicado pelo use case e de novo pelo
|
|
811
|
+
* adapter — este schema só recusa forma.
|
|
812
|
+
*/
|
|
813
|
+
export const zArtifactSignedUrlCommandSchema = z
|
|
814
|
+
.object({
|
|
815
|
+
disposition: zArtifactDispositionSchema.optional(),
|
|
816
|
+
ttl_seconds: z.number().int().min(30).max(900).optional(),
|
|
817
|
+
refresh: z.boolean().optional(),
|
|
818
|
+
})
|
|
819
|
+
.strict();
|
|
@@ -90,6 +90,7 @@ export declare const zContactSchema: z.ZodObject<{
|
|
|
90
90
|
type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
91
91
|
instagram: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
92
92
|
instagram_username: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
93
|
+
bsuid: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
93
94
|
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
94
95
|
email: z.ZodDefault<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
95
96
|
phone: z.ZodDefault<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
@@ -97,6 +98,7 @@ export declare const zContactSchema: z.ZodObject<{
|
|
|
97
98
|
type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
98
99
|
instagram: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
99
100
|
instagram_username: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
101
|
+
bsuid: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
100
102
|
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
101
103
|
email: z.ZodDefault<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
102
104
|
phone: z.ZodDefault<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
@@ -104,4 +106,5 @@ export declare const zContactSchema: z.ZodObject<{
|
|
|
104
106
|
type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
105
107
|
instagram: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
106
108
|
instagram_username: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
109
|
+
bsuid: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
107
110
|
}, z.ZodTypeAny, "passthrough">>;
|
|
@@ -89,4 +89,6 @@ exports.zContactSchema = zod_1.z.object({
|
|
|
89
89
|
type: zod_1.z.string().nullable().optional(),
|
|
90
90
|
instagram: zod_1.z.string().nullable().optional(),
|
|
91
91
|
instagram_username: zod_1.z.string().nullable().optional(),
|
|
92
|
+
// WhatsApp BSUID (Business-Scoped User ID) — contato que a Meta entrega sem telefone
|
|
93
|
+
bsuid: zod_1.z.string().nullable().optional(),
|
|
92
94
|
}).passthrough();
|
|
@@ -104,4 +104,6 @@ export const zContactSchema = z.object({
|
|
|
104
104
|
type: z.string().nullable().optional(),
|
|
105
105
|
instagram: z.string().nullable().optional(),
|
|
106
106
|
instagram_username: z.string().nullable().optional(),
|
|
107
|
+
// WhatsApp BSUID (Business-Scoped User ID) — contato que a Meta entrega sem telefone
|
|
108
|
+
bsuid: z.string().nullable().optional(),
|
|
107
109
|
}).passthrough();
|
|
@@ -49,6 +49,23 @@ export interface ICallsChannelConfig {
|
|
|
49
49
|
inbound_voice_enabled?: boolean;
|
|
50
50
|
outbound_permission?: ICallOutboundPermissionConfig;
|
|
51
51
|
}
|
|
52
|
+
export type WabaDirectSendCategory = 'utility' | 'authentication';
|
|
53
|
+
/** Restricao aplicada pela Meta ao Direct Send do WABA (webhook `account_update` / ACCOUNT_RESTRICTION). */
|
|
54
|
+
export interface IChannelDirectSendRestriction {
|
|
55
|
+
violation_type: string;
|
|
56
|
+
restriction_type?: string | null;
|
|
57
|
+
expiration?: Date | null;
|
|
58
|
+
received_at: Date;
|
|
59
|
+
}
|
|
60
|
+
/** Meta Direct Send (beta): envio iniciado pela empresa sem template previo. Desligado por padrao. */
|
|
61
|
+
export interface IChannelDirectSendConfig {
|
|
62
|
+
enabled: boolean;
|
|
63
|
+
categories?: WabaDirectSendCategory[];
|
|
64
|
+
default_ttl_seconds?: number | null;
|
|
65
|
+
/** Enquanto no futuro, o Direct Send do canal fica suspenso. */
|
|
66
|
+
restricted_until?: Date | null;
|
|
67
|
+
restriction?: IChannelDirectSendRestriction | null;
|
|
68
|
+
}
|
|
52
69
|
export interface IChannel extends IFireDoc {
|
|
53
70
|
model_ver: number;
|
|
54
71
|
provider: ChannelProvider | string;
|
|
@@ -61,6 +78,8 @@ export interface IChannel extends IFireDoc {
|
|
|
61
78
|
provider_ref: IChannelProviderRef;
|
|
62
79
|
hub_ia?: IHubIAConfig;
|
|
63
80
|
calls?: ICallsChannelConfig;
|
|
81
|
+
/** feat-165 — Meta Direct Send (beta). */
|
|
82
|
+
direct_send?: IChannelDirectSendConfig;
|
|
64
83
|
/** feat-142 — rollup da recepção do histórico de coexistência (WABA). */
|
|
65
84
|
history_import?: IChannelHistoryImport;
|
|
66
85
|
[key: string]: unknown;
|
|
@@ -71,6 +71,28 @@ export interface ICallsChannelConfig {
|
|
|
71
71
|
outbound_permission?: ICallOutboundPermissionConfig;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
// ── Direct Send config (feat-165) ──
|
|
75
|
+
|
|
76
|
+
export type WabaDirectSendCategory = 'utility' | 'authentication';
|
|
77
|
+
|
|
78
|
+
/** Restricao aplicada pela Meta ao Direct Send do WABA (webhook `account_update` / ACCOUNT_RESTRICTION). */
|
|
79
|
+
export interface IChannelDirectSendRestriction {
|
|
80
|
+
violation_type: string;
|
|
81
|
+
restriction_type?: string | null;
|
|
82
|
+
expiration?: Date | null;
|
|
83
|
+
received_at: Date;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Meta Direct Send (beta): envio iniciado pela empresa sem template previo. Desligado por padrao. */
|
|
87
|
+
export interface IChannelDirectSendConfig {
|
|
88
|
+
enabled: boolean;
|
|
89
|
+
categories?: WabaDirectSendCategory[];
|
|
90
|
+
default_ttl_seconds?: number | null;
|
|
91
|
+
/** Enquanto no futuro, o Direct Send do canal fica suspenso. */
|
|
92
|
+
restricted_until?: Date | null;
|
|
93
|
+
restriction?: IChannelDirectSendRestriction | null;
|
|
94
|
+
}
|
|
95
|
+
|
|
74
96
|
// ── Channel (evo-chat v3) ──
|
|
75
97
|
|
|
76
98
|
export interface IChannel extends IFireDoc {
|
|
@@ -85,6 +107,8 @@ export interface IChannel extends IFireDoc {
|
|
|
85
107
|
provider_ref: IChannelProviderRef;
|
|
86
108
|
hub_ia?: IHubIAConfig;
|
|
87
109
|
calls?: ICallsChannelConfig;
|
|
110
|
+
/** feat-165 — Meta Direct Send (beta). */
|
|
111
|
+
direct_send?: IChannelDirectSendConfig;
|
|
88
112
|
/** feat-142 — rollup da recepção do histórico de coexistência (WABA). */
|
|
89
113
|
history_import?: IChannelHistoryImport;
|
|
90
114
|
[key: string]: unknown;
|
|
@@ -13,6 +13,8 @@ export interface IMessageStatus {
|
|
|
13
13
|
}>;
|
|
14
14
|
error_code?: string;
|
|
15
15
|
error_message?: string;
|
|
16
|
+
/** feat-165 — id do template (inclusive o auto-gerado do Direct Send) informado no webhook de status. */
|
|
17
|
+
template_id?: string | null;
|
|
16
18
|
}
|
|
17
19
|
export interface IMessageMedia {
|
|
18
20
|
gcs_uri?: string;
|
|
@@ -68,6 +70,8 @@ export interface IMessageCreatedBy {
|
|
|
68
70
|
export interface IMessagePricing {
|
|
69
71
|
category?: 'service' | 'utility' | 'authentication' | 'marketing';
|
|
70
72
|
billable?: boolean;
|
|
73
|
+
/** feat-165 — `pricing.pricing_model` do webhook de status (ex.: PMP). */
|
|
74
|
+
pricing_model?: string | null;
|
|
71
75
|
}
|
|
72
76
|
export interface IRenderedTemplateButton {
|
|
73
77
|
type?: string;
|
|
@@ -22,6 +22,8 @@ export interface IMessageStatus {
|
|
|
22
22
|
errors?: Array<{ code: number; title: string }>;
|
|
23
23
|
error_code?: string;
|
|
24
24
|
error_message?: string;
|
|
25
|
+
/** feat-165 — id do template (inclusive o auto-gerado do Direct Send) informado no webhook de status. */
|
|
26
|
+
template_id?: string | null;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
// ── Message media ──
|
|
@@ -97,6 +99,8 @@ export interface IMessageCreatedBy {
|
|
|
97
99
|
export interface IMessagePricing {
|
|
98
100
|
category?: 'service' | 'utility' | 'authentication' | 'marketing';
|
|
99
101
|
billable?: boolean;
|
|
102
|
+
/** feat-165 — `pricing.pricing_model` do webhook de status (ex.: PMP). */
|
|
103
|
+
pricing_model?: string | null;
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
// ── Mensagem de template compilada (feat-114) ──
|
|
@@ -40,6 +40,8 @@ export declare const WabaTemplateParameterFormatEnum: {
|
|
|
40
40
|
readonly Positional: "POSITIONAL";
|
|
41
41
|
};
|
|
42
42
|
export type WabaTemplateParameterFormat = (typeof WabaTemplateParameterFormatEnum)[keyof typeof WabaTemplateParameterFormatEnum];
|
|
43
|
+
/** Valor de `source` dos templates criados pela Meta para mensagens Direct Send (nao editaveis/deletaveis). */
|
|
44
|
+
export declare const WABA_TEMPLATE_SOURCE_AUTO_GENERATED = "AUTO_GENERATED";
|
|
43
45
|
export interface IWabaTemplateButton {
|
|
44
46
|
type: WabaTemplateButtonType;
|
|
45
47
|
text: string;
|
|
@@ -83,6 +85,10 @@ export interface IWabaTemplate extends IFireDoc {
|
|
|
83
85
|
synced_at?: Date | null;
|
|
84
86
|
is_draft: boolean;
|
|
85
87
|
draft_source?: IWabaTemplateDraftSource;
|
|
88
|
+
/** Origem na Meta; `AUTO_GENERATED` = gerado pelo Direct Send. */
|
|
89
|
+
source?: string | null;
|
|
90
|
+
/** Categoria corrigida pela Meta (`template_correct_category_detection`). */
|
|
91
|
+
correct_category?: string | null;
|
|
86
92
|
}
|
|
87
93
|
export interface IWabaTemplateCreateRequest {
|
|
88
94
|
name: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WabaTemplateParameterFormatEnum = exports.WabaTemplateButtonTypeEnum = exports.WabaTemplateHeaderFormatEnum = exports.WabaTemplateComponentTypeEnum = exports.WabaTemplateCategoryEnum = exports.WabaTemplateStatusEnum = void 0;
|
|
3
|
+
exports.WABA_TEMPLATE_SOURCE_AUTO_GENERATED = exports.WabaTemplateParameterFormatEnum = exports.WabaTemplateButtonTypeEnum = exports.WabaTemplateHeaderFormatEnum = exports.WabaTemplateComponentTypeEnum = exports.WabaTemplateCategoryEnum = exports.WabaTemplateStatusEnum = void 0;
|
|
4
4
|
// ── Enums ──
|
|
5
5
|
exports.WabaTemplateStatusEnum = {
|
|
6
6
|
Draft: 'DRAFT',
|
|
@@ -37,3 +37,5 @@ exports.WabaTemplateParameterFormatEnum = {
|
|
|
37
37
|
Named: 'NAMED',
|
|
38
38
|
Positional: 'POSITIONAL',
|
|
39
39
|
};
|
|
40
|
+
/** Valor de `source` dos templates criados pela Meta para mensagens Direct Send (nao editaveis/deletaveis). */
|
|
41
|
+
exports.WABA_TEMPLATE_SOURCE_AUTO_GENERATED = 'AUTO_GENERATED';
|
|
@@ -49,6 +49,9 @@ export const WabaTemplateParameterFormatEnum = {
|
|
|
49
49
|
} as const;
|
|
50
50
|
export type WabaTemplateParameterFormat = (typeof WabaTemplateParameterFormatEnum)[keyof typeof WabaTemplateParameterFormatEnum];
|
|
51
51
|
|
|
52
|
+
/** Valor de `source` dos templates criados pela Meta para mensagens Direct Send (nao editaveis/deletaveis). */
|
|
53
|
+
export const WABA_TEMPLATE_SOURCE_AUTO_GENERATED = 'AUTO_GENERATED';
|
|
54
|
+
|
|
52
55
|
// ── Component types ──
|
|
53
56
|
|
|
54
57
|
export interface IWabaTemplateButton {
|
|
@@ -95,6 +98,10 @@ export interface IWabaTemplate extends IFireDoc {
|
|
|
95
98
|
synced_at?: Date | null;
|
|
96
99
|
is_draft: boolean;
|
|
97
100
|
draft_source?: IWabaTemplateDraftSource;
|
|
101
|
+
/** Origem na Meta; `AUTO_GENERATED` = gerado pelo Direct Send. */
|
|
102
|
+
source?: string | null;
|
|
103
|
+
/** Categoria corrigida pela Meta (`template_correct_category_detection`). */
|
|
104
|
+
correct_category?: string | null;
|
|
98
105
|
}
|
|
99
106
|
|
|
100
107
|
// ── Request types ──
|
|
@@ -76,6 +76,14 @@ export declare const NexFinopsMetricCatalog: {
|
|
|
76
76
|
readonly label: "E-mails enviados";
|
|
77
77
|
readonly unit: "mensagens";
|
|
78
78
|
};
|
|
79
|
+
readonly teleconsultations_unrecorded: {
|
|
80
|
+
readonly label: "Teleconsultas sem gravação";
|
|
81
|
+
readonly unit: "consultas";
|
|
82
|
+
};
|
|
83
|
+
readonly teleconsultations_recorded: {
|
|
84
|
+
readonly label: "Teleconsultas com gravação";
|
|
85
|
+
readonly unit: "consultas";
|
|
86
|
+
};
|
|
79
87
|
};
|
|
80
88
|
/**
|
|
81
89
|
* Chaves conhecidas do catálogo — para iterar e para tipar escolha de métrica
|
|
@@ -11,6 +11,13 @@ exports.NexFinopsMetricCatalog = {
|
|
|
11
11
|
attendances: { label: 'Atendimentos', unit: 'contatos' },
|
|
12
12
|
sms: { label: 'SMS enviados', unit: 'mensagens' },
|
|
13
13
|
email: { label: 'E-mails enviados', unit: 'mensagens' },
|
|
14
|
+
// feat-160 F18 (D33) — DISJUNTAS: uma teleconsulta realizada consome
|
|
15
|
+
// exatamente UMA das duas. `_recorded` NAO e subconjunto de um total; o total
|
|
16
|
+
// e derivado na tela. A transcricao esta dentro de `_recorded`, nao tem
|
|
17
|
+
// franquia propria. Ler uma como subconjunto da outra cobra o mesmo encontro
|
|
18
|
+
// duas vezes.
|
|
19
|
+
teleconsultations_unrecorded: { label: 'Teleconsultas sem gravação', unit: 'consultas' },
|
|
20
|
+
teleconsultations_recorded: { label: 'Teleconsultas com gravação', unit: 'consultas' },
|
|
14
21
|
};
|
|
15
22
|
/** Doc de config global dos alertas de consumo (convenção `/platform/<app>`). */
|
|
16
23
|
exports.EVO_BILLING_USAGE_ALERTS_CONFIG_PATH = 'platform/evo-billing/usage-alerts/config';
|
|
@@ -80,6 +80,13 @@ export const NexFinopsMetricCatalog = {
|
|
|
80
80
|
attendances: { label: 'Atendimentos', unit: 'contatos' },
|
|
81
81
|
sms: { label: 'SMS enviados', unit: 'mensagens' },
|
|
82
82
|
email: { label: 'E-mails enviados', unit: 'mensagens' },
|
|
83
|
+
// feat-160 F18 (D33) — DISJUNTAS: uma teleconsulta realizada consome
|
|
84
|
+
// exatamente UMA das duas. `_recorded` NAO e subconjunto de um total; o total
|
|
85
|
+
// e derivado na tela. A transcricao esta dentro de `_recorded`, nao tem
|
|
86
|
+
// franquia propria. Ler uma como subconjunto da outra cobra o mesmo encontro
|
|
87
|
+
// duas vezes.
|
|
88
|
+
teleconsultations_unrecorded: { label: 'Teleconsultas sem gravação', unit: 'consultas' },
|
|
89
|
+
teleconsultations_recorded: { label: 'Teleconsultas com gravação', unit: 'consultas' },
|
|
83
90
|
} as const;
|
|
84
91
|
|
|
85
92
|
/**
|
|
@@ -47,6 +47,29 @@ export interface IMedCalendarNotificationConfig {
|
|
|
47
47
|
configs?: {
|
|
48
48
|
[configKey: string]: IMedCalendarNotificationEntry;
|
|
49
49
|
} | null;
|
|
50
|
+
/**
|
|
51
|
+
* feat-160 (§10.2) — MESMA forma de `configs`, mas só para agendamento com
|
|
52
|
+
* `appointmentMode === 'telemedicine'`.
|
|
53
|
+
*
|
|
54
|
+
* **Semântica de HERANÇA, resolvida em UM lugar** (`@evo/model`
|
|
55
|
+
* `calendar-notification-config.ts` → `resolveNotificationConfigEntry(config,
|
|
56
|
+
* configKey, mode)`); nenhum leitor decide sozinho:
|
|
57
|
+
*
|
|
58
|
+
* - modo `telemedicine` e a chave EXISTE aqui ⇒ vale esta entrada, inclusive
|
|
59
|
+
* com `enabled: false` (é exatamente assim que a clínica desliga um aviso
|
|
60
|
+
* SÓ na telemedicina sem mexer no presencial);
|
|
61
|
+
* - modo `telemedicine` e a chave NÃO existe aqui ⇒ HERDA `configs[configKey]`;
|
|
62
|
+
* - modo presencial (ou ausente) ⇒ `configs[configKey]`, este bloco é ignorado.
|
|
63
|
+
*
|
|
64
|
+
* Chave ausente ≠ chave com `enabled:false`: a primeira herda, a segunda
|
|
65
|
+
* desliga. É a única distinção que o editor do FE precisa expressar ("herdar
|
|
66
|
+
* do presencial" = remover a chave).
|
|
67
|
+
*
|
|
68
|
+
* Ausência do bloco inteiro = comportamento pré-feat-160 (toda agenda hoje).
|
|
69
|
+
*/
|
|
70
|
+
telemedicine_configs?: {
|
|
71
|
+
[configKey: string]: IMedCalendarNotificationEntry;
|
|
72
|
+
} | null;
|
|
50
73
|
}
|
|
51
74
|
/** Uma config de notificação (feat-092): um evento/momento × seus canais. */
|
|
52
75
|
export interface IMedCalendarNotificationEntry {
|
|
@@ -74,8 +97,10 @@ export interface IMedCalendarNotificationChannelEntry {
|
|
|
74
97
|
department_id?: string | null;
|
|
75
98
|
/** Template principal da mensagem (HSM name no WA / template_id lógico no email). */
|
|
76
99
|
template_id?: string | null;
|
|
77
|
-
/** Tipo do template principal: 'hsm' | 'email' | … O leitor pode inferir pelo canal. */
|
|
100
|
+
/** Tipo do template principal: 'hsm' | 'quick_reply' | 'direct_send' | 'email' | … O leitor pode inferir pelo canal. */
|
|
78
101
|
template_type?: string | null;
|
|
102
|
+
/** feat-165 — texto (com tokens) enviado quando `template_type === 'direct_send'`. */
|
|
103
|
+
direct_send_text?: string | null;
|
|
79
104
|
/** Botões/ações da mensagem → artefato de resposta de cada um. */
|
|
80
105
|
ctas?: IMedCalendarNotificationCta[] | null;
|
|
81
106
|
}
|
|
@@ -131,6 +156,93 @@ export declare const MedCalendarNotificationConfigKeys: {
|
|
|
131
156
|
readonly TelemedicineJoinReminder: "telemedicine_join_reminder";
|
|
132
157
|
};
|
|
133
158
|
export type MedCalendarNotificationConfigKey = (typeof MedCalendarNotificationConfigKeys)[keyof typeof MedCalendarNotificationConfigKeys];
|
|
159
|
+
/** `recording.mode` da agenda (feat-160 F15). `off` esconde "Solicitar gravação". */
|
|
160
|
+
export declare const VirtualCareRecordingModeEnum: {
|
|
161
|
+
/** Gravação indisponível nesta agenda. */
|
|
162
|
+
readonly Off: "off";
|
|
163
|
+
/** Médico solicita em sala e o paciente aceita ali (comportamento do MVP). */
|
|
164
|
+
readonly Manual: "manual";
|
|
165
|
+
/** Inicia sozinha, só áudio; o aceite é colhido ANTES de o paciente entrar. */
|
|
166
|
+
readonly AutoAudio: "auto_audio";
|
|
167
|
+
/** Idem, com vídeo. */
|
|
168
|
+
readonly AutoVideo: "auto_video";
|
|
169
|
+
};
|
|
170
|
+
export type VirtualCareRecordingMode = (typeof VirtualCareRecordingModeEnum)[keyof typeof VirtualCareRecordingModeEnum];
|
|
171
|
+
/** Limites de `recording.retention_days` (D32; D13 mantém 7 como default). */
|
|
172
|
+
export declare const VIRTUAL_CARE_RETENTION_DAYS_MIN = 7;
|
|
173
|
+
export declare const VIRTUAL_CARE_RETENTION_DAYS_MAX = 730;
|
|
174
|
+
/** Limites de `max_duration_minutes`. */
|
|
175
|
+
export declare const VIRTUAL_CARE_MAX_DURATION_MINUTES_MIN = 15;
|
|
176
|
+
export declare const VIRTUAL_CARE_MAX_DURATION_MINUTES_MAX = 480;
|
|
177
|
+
/** O que está GRAVADO no doc da agenda — tudo parcial (ausente = default). */
|
|
178
|
+
export interface IMedCalendarVirtualCareConfig {
|
|
179
|
+
/**
|
|
180
|
+
* Admite o paciente sozinho quando o médico já está em sala
|
|
181
|
+
* (`waiting_policy` default `auto_when_doctor_present`). Exige a capability
|
|
182
|
+
* `auto_admit` do entitlement e NUNCA vale sem identidade verificada (D9).
|
|
183
|
+
*/
|
|
184
|
+
auto_admit?: boolean | null;
|
|
185
|
+
recording?: {
|
|
186
|
+
mode?: VirtualCareRecordingMode | null;
|
|
187
|
+
/** Transcrição da gravação. Gate D12 + capability `transcription`. */
|
|
188
|
+
transcription?: boolean | null;
|
|
189
|
+
/**
|
|
190
|
+
* Retenção de gravação/transcrição em dias, 7..730 (D32). O sweep é a
|
|
191
|
+
* verdade (`artifact.expires_at` = fim + N dias); o lifecycle do bucket é
|
|
192
|
+
* só defesa de último caso. O prazo escolhido entra no texto de gravação
|
|
193
|
+
* mostrado ao paciente (`{{retention}}`).
|
|
194
|
+
*/
|
|
195
|
+
retention_days?: number | null;
|
|
196
|
+
} | null;
|
|
197
|
+
identity?: {
|
|
198
|
+
require_name?: boolean | null;
|
|
199
|
+
/** Só é exigível quando o cadastro TEM data de nascimento (spec §8.3). */
|
|
200
|
+
require_birth_date?: boolean | null;
|
|
201
|
+
/** `true` ⇒ `identity_level: 'weak'`; nunca habilita auto-admit (D9). */
|
|
202
|
+
skip?: boolean | null;
|
|
203
|
+
} | null;
|
|
204
|
+
/** Antecedência de acesso à sala, por papel, em minutos. */
|
|
205
|
+
allow_early_start_minutes?: {
|
|
206
|
+
doctor?: number | null;
|
|
207
|
+
patient?: number | null;
|
|
208
|
+
} | null;
|
|
209
|
+
/** `true` = passar do fim previsto não encerra a consulta (comportamento atual). */
|
|
210
|
+
allow_late_end?: boolean | null;
|
|
211
|
+
/** Teto absoluto; o sweep encerra ao exceder (`reason: max_duration`). 15..480. */
|
|
212
|
+
max_duration_minutes?: number | null;
|
|
213
|
+
/** Aviso ao médico no SPA quando faltar N min para o fim. 0 = sem aviso. */
|
|
214
|
+
end_warning_minutes?: number | null;
|
|
215
|
+
}
|
|
216
|
+
/** Config já RESOLVIDA (doc + defaults) — é com isto que o backend decide. */
|
|
217
|
+
export interface IMedCalendarVirtualCareSettings {
|
|
218
|
+
auto_admit: boolean;
|
|
219
|
+
recording: {
|
|
220
|
+
mode: VirtualCareRecordingMode;
|
|
221
|
+
transcription: boolean;
|
|
222
|
+
retention_days: number;
|
|
223
|
+
};
|
|
224
|
+
identity: {
|
|
225
|
+
require_name: boolean;
|
|
226
|
+
require_birth_date: boolean;
|
|
227
|
+
skip: boolean;
|
|
228
|
+
};
|
|
229
|
+
allow_early_start_minutes: {
|
|
230
|
+
doctor: number;
|
|
231
|
+
patient: number;
|
|
232
|
+
};
|
|
233
|
+
allow_late_end: boolean;
|
|
234
|
+
max_duration_minutes: number;
|
|
235
|
+
end_warning_minutes: number;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Defaults da spec (plan §12 / D13 / D32). Agenda sem `virtual_care` vale
|
|
239
|
+
* exatamente isto — é o que faz "sem migração de dado" ser verdade.
|
|
240
|
+
*
|
|
241
|
+
* Congelado (`as const` + `Readonly`) de propósito: é referência compartilhada,
|
|
242
|
+
* e um consumidor que mutasse um nível aninhado mudaria o default de todos.
|
|
243
|
+
* Para resolver, faça merge por nível (`{ ...DEFAULTS.recording, ...cfg.recording }`).
|
|
244
|
+
*/
|
|
245
|
+
export declare const CALENDAR_VIRTUAL_CARE_DEFAULTS: IMedCalendarVirtualCareSettings;
|
|
134
246
|
export interface IMedCalendar extends IFireDoc {
|
|
135
247
|
calendarId: string;
|
|
136
248
|
color?: string;
|
|
@@ -160,5 +272,16 @@ export interface IMedCalendar extends IFireDoc {
|
|
|
160
272
|
available_for_hubia?: boolean | null;
|
|
161
273
|
integration?: IMedCalendarIntegration | null;
|
|
162
274
|
notification_config?: IMedCalendarNotificationConfig | null;
|
|
275
|
+
/**
|
|
276
|
+
* Config de telemedicina por-agenda (feat-160 F16). Ausente = defaults de
|
|
277
|
+
* `CALENDAR_VIRTUAL_CARE_DEFAULTS`; só tem efeito com `modules.telemedicine`.
|
|
278
|
+
*/
|
|
279
|
+
virtual_care?: IMedCalendarVirtualCareConfig | null;
|
|
280
|
+
/**
|
|
281
|
+
* Profissional (médico) padrão da agenda — feat-160 F16, fora do módulo de
|
|
282
|
+
* telemedicina (pedido do usuário, mesmo editor). Ref para
|
|
283
|
+
* `tenants/{t}/apps/evo-med/professionals/{id}`; `null` = sem padrão.
|
|
284
|
+
*/
|
|
285
|
+
default_professional_ref?: FirestoreDocumentReference | null;
|
|
163
286
|
[key: string]: unknown;
|
|
164
287
|
}
|
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.MedCalendarNotificationConfigKeys = exports.EvoMedCalendarPermissions = void 0;
|
|
17
|
+
exports.CALENDAR_VIRTUAL_CARE_DEFAULTS = exports.VIRTUAL_CARE_MAX_DURATION_MINUTES_MAX = exports.VIRTUAL_CARE_MAX_DURATION_MINUTES_MIN = exports.VIRTUAL_CARE_RETENTION_DAYS_MAX = exports.VIRTUAL_CARE_RETENTION_DAYS_MIN = exports.VirtualCareRecordingModeEnum = exports.MedCalendarNotificationConfigKeys = exports.EvoMedCalendarPermissions = void 0;
|
|
18
18
|
__exportStar(require("../../evo-people/fb_collections"), exports);
|
|
19
19
|
// Permissões para o calendário
|
|
20
20
|
exports.EvoMedCalendarPermissions = {
|
|
@@ -66,3 +66,62 @@ exports.MedCalendarNotificationConfigKeys = {
|
|
|
66
66
|
*/
|
|
67
67
|
TelemedicineJoinReminder: "telemedicine_join_reminder",
|
|
68
68
|
};
|
|
69
|
+
// ----- Virtual Care (inline no calendar doc) — feat-160 F16
|
|
70
|
+
// Config por-agenda do módulo de telemedicina ("Hub Médica Virtual Care"), lida
|
|
71
|
+
// pelo backend no `join`/`admit`/sweep e editada na seção própria do Calendar V2
|
|
72
|
+
// (visível só com o entitlement `modules.telemedicine`).
|
|
73
|
+
//
|
|
74
|
+
// Bloco e campos são TODOS opcionais: agenda sem o bloco (a maioria) vale
|
|
75
|
+
// exatamente `CALENDAR_VIRTUAL_CARE_DEFAULTS`, sem migração de dado (plan §12).
|
|
76
|
+
// Por isso existem DOIS tipos: `IMedCalendarVirtualCareConfig` é o que está
|
|
77
|
+
// gravado (parcial), e `IMedCalendarVirtualCareSettings` é o resultado de
|
|
78
|
+
// aplicar os defaults sobre ele — o que o backend efetivamente decide com.
|
|
79
|
+
//
|
|
80
|
+
// `| null` em todo campo, como no `notification_config`: o editor do FE grava
|
|
81
|
+
// "não escolhido" como `null` explícito e `.passthrough()` não cobre null em
|
|
82
|
+
// chave declarada — sem `.nullable()` o doc inteiro do calendário reprovaria.
|
|
83
|
+
/** `recording.mode` da agenda (feat-160 F15). `off` esconde "Solicitar gravação". */
|
|
84
|
+
exports.VirtualCareRecordingModeEnum = {
|
|
85
|
+
/** Gravação indisponível nesta agenda. */
|
|
86
|
+
Off: "off",
|
|
87
|
+
/** Médico solicita em sala e o paciente aceita ali (comportamento do MVP). */
|
|
88
|
+
Manual: "manual",
|
|
89
|
+
/** Inicia sozinha, só áudio; o aceite é colhido ANTES de o paciente entrar. */
|
|
90
|
+
AutoAudio: "auto_audio",
|
|
91
|
+
/** Idem, com vídeo. */
|
|
92
|
+
AutoVideo: "auto_video",
|
|
93
|
+
};
|
|
94
|
+
/** Limites de `recording.retention_days` (D32; D13 mantém 7 como default). */
|
|
95
|
+
exports.VIRTUAL_CARE_RETENTION_DAYS_MIN = 7;
|
|
96
|
+
exports.VIRTUAL_CARE_RETENTION_DAYS_MAX = 730;
|
|
97
|
+
/** Limites de `max_duration_minutes`. */
|
|
98
|
+
exports.VIRTUAL_CARE_MAX_DURATION_MINUTES_MIN = 15;
|
|
99
|
+
exports.VIRTUAL_CARE_MAX_DURATION_MINUTES_MAX = 480;
|
|
100
|
+
/**
|
|
101
|
+
* Defaults da spec (plan §12 / D13 / D32). Agenda sem `virtual_care` vale
|
|
102
|
+
* exatamente isto — é o que faz "sem migração de dado" ser verdade.
|
|
103
|
+
*
|
|
104
|
+
* Congelado (`as const` + `Readonly`) de propósito: é referência compartilhada,
|
|
105
|
+
* e um consumidor que mutasse um nível aninhado mudaria o default de todos.
|
|
106
|
+
* Para resolver, faça merge por nível (`{ ...DEFAULTS.recording, ...cfg.recording }`).
|
|
107
|
+
*/
|
|
108
|
+
exports.CALENDAR_VIRTUAL_CARE_DEFAULTS = {
|
|
109
|
+
auto_admit: false,
|
|
110
|
+
recording: {
|
|
111
|
+
mode: exports.VirtualCareRecordingModeEnum.Manual,
|
|
112
|
+
transcription: false,
|
|
113
|
+
retention_days: exports.VIRTUAL_CARE_RETENTION_DAYS_MIN,
|
|
114
|
+
},
|
|
115
|
+
identity: {
|
|
116
|
+
require_name: true,
|
|
117
|
+
require_birth_date: true,
|
|
118
|
+
skip: false,
|
|
119
|
+
},
|
|
120
|
+
allow_early_start_minutes: {
|
|
121
|
+
doctor: 30,
|
|
122
|
+
patient: 15,
|
|
123
|
+
},
|
|
124
|
+
allow_late_end: true,
|
|
125
|
+
max_duration_minutes: 120,
|
|
126
|
+
end_warning_minutes: 5,
|
|
127
|
+
};
|