evo360-types 1.3.512 → 1.3.516

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.
@@ -739,3 +739,185 @@ export const zServiceInvoiceSchema = zFireDocSchema
739
739
  snapshots: z.array(zProviderPayloadSnapshotSchema).optional(),
740
740
  })
741
741
  .passthrough();
742
+
743
+ // ---- Nexus FinOps Proposal (feat-128) ----
744
+
745
+ export const zNexFinopsProposalStatusSchema = z.enum([
746
+ "draft",
747
+ "sent",
748
+ "viewed",
749
+ "accepted",
750
+ "expired",
751
+ "canceled",
752
+ ]);
753
+
754
+ export const zNexFinopsProposalPaymentMethodSchema = z.enum([
755
+ "boleto",
756
+ "card_subscription",
757
+ "payment_link",
758
+ ]);
759
+
760
+ export const zNexFinopsProposalPrefillSchema = z
761
+ .object({
762
+ name: z.string().max(255).nullable().optional(),
763
+ email: z.string().max(255).nullable().optional(),
764
+ phone: z.string().max(50).nullable().optional(),
765
+ company: z.string().max(255).nullable().optional(),
766
+ })
767
+ .passthrough();
768
+
769
+ /**
770
+ * Payload de escrita da proposta (fronteira HTTP). Campos opcionais usam
771
+ * `.nullable()` além de `.optional()` porque o cliente pode mandar `null`
772
+ * explícito (Vuetify `clearable` grava null; callable converte undefined em null).
773
+ *
774
+ * `short_code`, `status` e `currency` NÃO entram aqui: são resolvidos no servidor.
775
+ */
776
+ export const zNexFinopsProposalWriteSchema = z
777
+ .object({
778
+ origem: z.string().min(1).max(64).optional(),
779
+ customer_id: z.string().max(128).nullable().optional(),
780
+ customer_ref: z.string().max(512).nullable().optional(),
781
+ prefill: zNexFinopsProposalPrefillSchema.nullable().optional(),
782
+ name: z.string().max(255).nullable().optional(),
783
+ html_content: z.string().optional(),
784
+ base_amount: z.number().nonnegative().optional(),
785
+ due_day: z.number().int().min(1).max(31).optional(),
786
+ accepted_payment_methods: z.array(zNexFinopsProposalPaymentMethodSchema).optional(),
787
+ terms: z.string().nullable().optional(),
788
+ valid_until: z
789
+ .string()
790
+ .regex(/^\d{4}-\d{2}-\d{2}$/, "valid_until must be an ISO date (YYYY-MM-DD)")
791
+ .optional(),
792
+ notes: z.string().nullable().optional(),
793
+ })
794
+ .strip();
795
+
796
+ export const zNexFinopsProposalSchema = zNexFinopsProposalWriteSchema.extend({
797
+ short_code: z.string().min(1),
798
+ status: zNexFinopsProposalStatusSchema,
799
+ currency: z.literal("BRL"),
800
+ });
801
+
802
+ // ---- Nexus FinOps / Vendas Payment (feat-131) ----
803
+
804
+ export const zNexFinopsPaymentMethodSchema = z.enum([
805
+ "pix",
806
+ "boleto",
807
+ "payment_link",
808
+ "card_subscription",
809
+ ]);
810
+
811
+ export const zNexFinopsAsaasSubscriptionStatusSchema = z.enum([
812
+ "ACTIVE",
813
+ "EXPIRED",
814
+ "INACTIVE",
815
+ ]);
816
+
817
+ /**
818
+ * Vínculo contrato ↔ assinatura Asaas. O checkout é hospedado (SAQ-A): nunca
819
+ * existe campo de número completo, CCV ou token de cartão neste schema.
820
+ */
821
+ export const zNexFinopsContractAsaasInfoSchema = z
822
+ .object({
823
+ customer_id: z.string().max(128).optional().nullable(),
824
+ subscription_id: z.string().max(128).optional().nullable(),
825
+ subscription_status: zNexFinopsAsaasSubscriptionStatusSchema.optional().nullable(),
826
+ cycle: z.string().max(32).optional().nullable(),
827
+ value: z.number().nonnegative().optional().nullable(),
828
+ next_due_date: z
829
+ .string()
830
+ .regex(/^\d{4}-\d{2}-\d{2}$/, "next_due_date must be an ISO date (YYYY-MM-DD)")
831
+ .optional()
832
+ .nullable(),
833
+ card_last4: z.string().max(4).optional().nullable(),
834
+ card_brand: z.string().max(32).optional().nullable(),
835
+ checkout_id: z.string().max(128).optional().nullable(),
836
+ env: z.enum(["sandbox", "production"]).optional().nullable(),
837
+ })
838
+ .strip();
839
+
840
+ export const zNexVendasJourneyPaymentMethodSchema = z.enum([
841
+ "card_subscription",
842
+ "boleto",
843
+ "payment_link",
844
+ ]);
845
+
846
+ export const zNexVendasJourneyPaymentKindSchema = z.enum([
847
+ "asaas_checkout",
848
+ "boleto",
849
+ "payment_link",
850
+ ]);
851
+
852
+ export const zNexVendasJourneyPaymentStateSchema = z.enum([
853
+ "none",
854
+ "awaiting_payment",
855
+ "compensating",
856
+ "paid",
857
+ ]);
858
+
859
+ /** Body de `POST /journeys/:short_code/payment`. */
860
+ export const zNexVendasJourneyPaymentChooseSchema = z
861
+ .object({
862
+ method: zNexVendasJourneyPaymentMethodSchema,
863
+ })
864
+ .strip();
865
+
866
+ export const zNexVendasJourneyBoletoSchema = z
867
+ .object({
868
+ payment_id: z.string().max(128).optional().nullable(),
869
+ invoice_url: z.string().max(2048).optional().nullable(),
870
+ bank_slip_url: z.string().max(2048).optional().nullable(),
871
+ pix_qr_code: z.string().optional().nullable(),
872
+ pix_copy_paste: z.string().optional().nullable(),
873
+ due_date: z
874
+ .string()
875
+ .regex(/^\d{4}-\d{2}-\d{2}$/, "due_date must be an ISO date (YYYY-MM-DD)")
876
+ .optional()
877
+ .nullable(),
878
+ value: z.number().nonnegative().optional().nullable(),
879
+ })
880
+ .strip();
881
+
882
+ export const zNexVendasJourneyPaymentWebhookEventSchema = z
883
+ .object({
884
+ event: z.string().min(1).max(64),
885
+ payment_id: z.string().max(128).optional().nullable(),
886
+ payment_status: z.string().max(64).optional().nullable(),
887
+ subscription_id: z.string().max(128).optional().nullable(),
888
+ at: zFirestoreDateSchema,
889
+ })
890
+ .strip();
891
+
892
+ export const zNexVendasJourneyPaymentSupersededSchema = z
893
+ .object({
894
+ method: zNexVendasJourneyPaymentMethodSchema,
895
+ kind: zNexVendasJourneyPaymentKindSchema,
896
+ checkout_id: z.string().max(128).optional().nullable(),
897
+ payment_id: z.string().max(128).optional().nullable(),
898
+ payment_link_id: z.string().max(128).optional().nullable(),
899
+ at: zFirestoreDateSchema,
900
+ revoked: z.boolean().optional().nullable(),
901
+ })
902
+ .strip();
903
+
904
+ export const zNexVendasJourneyPaymentSchema = z
905
+ .object({
906
+ state: zNexVendasJourneyPaymentStateSchema,
907
+ method: zNexVendasJourneyPaymentMethodSchema.optional().nullable(),
908
+ kind: zNexVendasJourneyPaymentKindSchema.optional().nullable(),
909
+ checkout_id: z.string().max(128).optional().nullable(),
910
+ redirect_url: z.string().max(2048).optional().nullable(),
911
+ expires_at: zFirestoreDateSchema.optional().nullable(),
912
+ boleto: zNexVendasJourneyBoletoSchema.optional().nullable(),
913
+ payment_link_id: z.string().max(128).optional().nullable(),
914
+ link: z.string().max(2048).optional().nullable(),
915
+ first_payment_id: z.string().max(128).optional().nullable(),
916
+ subscription_id: z.string().max(128).optional().nullable(),
917
+ paid_at: zFirestoreDateSchema.optional().nullable(),
918
+ created_at: zFirestoreDateSchema.optional().nullable(),
919
+ webhook_events: z.array(zNexVendasJourneyPaymentWebhookEventSchema).optional().nullable(),
920
+ superseded: z.array(zNexVendasJourneyPaymentSupersededSchema).optional().nullable(),
921
+ last_error: z.string().optional().nullable(),
922
+ })
923
+ .strip();
@@ -44,7 +44,6 @@ export declare const zTissConfigSchema: z.ZodObject<{
44
44
  }, "strip", z.ZodTypeAny, {
45
45
  version: string;
46
46
  active: boolean;
47
- current_batch: number;
48
47
  contract: {
49
48
  name: string;
50
49
  type: "PJ" | "PF";
@@ -52,10 +51,10 @@ export declare const zTissConfigSchema: z.ZodObject<{
52
51
  taxId: string;
53
52
  cnes: string;
54
53
  };
54
+ current_batch: number;
55
55
  }, {
56
56
  version: string;
57
57
  active: boolean;
58
- current_batch: number;
59
58
  contract: {
60
59
  name: string;
61
60
  type: "PJ" | "PF";
@@ -63,6 +62,7 @@ export declare const zTissConfigSchema: z.ZodObject<{
63
62
  taxId: string;
64
63
  cnes: string;
65
64
  };
65
+ current_batch: number;
66
66
  }>;
67
67
  export declare const zInsuranceCompanySchema: z.ZodObject<{
68
68
  id: z.ZodString;
@@ -105,7 +105,6 @@ export declare const zInsuranceCompanySchema: z.ZodObject<{
105
105
  }, "strip", z.ZodTypeAny, {
106
106
  version: string;
107
107
  active: boolean;
108
- current_batch: number;
109
108
  contract: {
110
109
  name: string;
111
110
  type: "PJ" | "PF";
@@ -113,10 +112,10 @@ export declare const zInsuranceCompanySchema: z.ZodObject<{
113
112
  taxId: string;
114
113
  cnes: string;
115
114
  };
115
+ current_batch: number;
116
116
  }, {
117
117
  version: string;
118
118
  active: boolean;
119
- current_batch: number;
120
119
  contract: {
121
120
  name: string;
122
121
  type: "PJ" | "PF";
@@ -124,6 +123,7 @@ export declare const zInsuranceCompanySchema: z.ZodObject<{
124
123
  taxId: string;
125
124
  cnes: string;
126
125
  };
126
+ current_batch: number;
127
127
  }>>;
128
128
  address: z.ZodOptional<z.ZodObject<{
129
129
  name: z.ZodDefault<z.ZodOptional<z.ZodString>>;
@@ -241,7 +241,6 @@ export declare const zInsuranceCompanySchema: z.ZodObject<{
241
241
  }, "strip", z.ZodTypeAny, {
242
242
  version: string;
243
243
  active: boolean;
244
- current_batch: number;
245
244
  contract: {
246
245
  name: string;
247
246
  type: "PJ" | "PF";
@@ -249,10 +248,10 @@ export declare const zInsuranceCompanySchema: z.ZodObject<{
249
248
  taxId: string;
250
249
  cnes: string;
251
250
  };
251
+ current_batch: number;
252
252
  }, {
253
253
  version: string;
254
254
  active: boolean;
255
- current_batch: number;
256
255
  contract: {
257
256
  name: string;
258
257
  type: "PJ" | "PF";
@@ -260,6 +259,7 @@ export declare const zInsuranceCompanySchema: z.ZodObject<{
260
259
  taxId: string;
261
260
  cnes: string;
262
261
  };
262
+ current_batch: number;
263
263
  }>>;
264
264
  address: z.ZodOptional<z.ZodObject<{
265
265
  name: z.ZodDefault<z.ZodOptional<z.ZodString>>;
@@ -377,7 +377,6 @@ export declare const zInsuranceCompanySchema: z.ZodObject<{
377
377
  }, "strip", z.ZodTypeAny, {
378
378
  version: string;
379
379
  active: boolean;
380
- current_batch: number;
381
380
  contract: {
382
381
  name: string;
383
382
  type: "PJ" | "PF";
@@ -385,10 +384,10 @@ export declare const zInsuranceCompanySchema: z.ZodObject<{
385
384
  taxId: string;
386
385
  cnes: string;
387
386
  };
387
+ current_batch: number;
388
388
  }, {
389
389
  version: string;
390
390
  active: boolean;
391
- current_batch: number;
392
391
  contract: {
393
392
  name: string;
394
393
  type: "PJ" | "PF";
@@ -396,6 +395,7 @@ export declare const zInsuranceCompanySchema: z.ZodObject<{
396
395
  taxId: string;
397
396
  cnes: string;
398
397
  };
398
+ current_batch: number;
399
399
  }>>;
400
400
  address: z.ZodOptional<z.ZodObject<{
401
401
  name: z.ZodDefault<z.ZodOptional<z.ZodString>>;
package/dist/index.d.ts CHANGED
@@ -29,6 +29,7 @@ export * from "./types/domain-events";
29
29
  export * from "./types/evo-integrations";
30
30
  export * from "./types/nex-customers";
31
31
  export * from "./types/nex-tenants";
32
+ export * from "./types/nex-vendas";
32
33
  export * from "./types/nexus-webhooks";
33
34
  export * from "./types/evo-hub-ia";
34
35
  export * from "./types/evo-mcp";
package/dist/index.js CHANGED
@@ -46,6 +46,7 @@ __exportStar(require("./types/domain-events"), exports);
46
46
  __exportStar(require("./types/evo-integrations"), exports);
47
47
  __exportStar(require("./types/nex-customers"), exports);
48
48
  __exportStar(require("./types/nex-tenants"), exports);
49
+ __exportStar(require("./types/nex-vendas"), exports);
49
50
  __exportStar(require("./types/nexus-webhooks"), exports);
50
51
  __exportStar(require("./types/evo-hub-ia"), exports);
51
52
  __exportStar(require("./types/evo-mcp"), exports);
package/dist/index.ts CHANGED
@@ -30,6 +30,7 @@ export * from "./types/domain-events";
30
30
  export * from "./types/evo-integrations";
31
31
  export * from "./types/nex-customers";
32
32
  export * from "./types/nex-tenants";
33
+ export * from "./types/nex-vendas";
33
34
  export * from "./types/nexus-webhooks";
34
35
  export * from "./types/evo-hub-ia";
35
36
  export * from "./types/evo-mcp";
@@ -7,12 +7,35 @@ export interface SearchThreadsParams {
7
7
  department_ids?: string[];
8
8
  attendant_type?: SearchAttendantType;
9
9
  assigned_user_id?: string;
10
+ /** Atendente que ENCERROU algum ticket da conversa na janela. */
11
+ closed_by_user_id?: string;
12
+ close_codes?: string[];
10
13
  tag_ids?: string[];
11
14
  /** Free-text contains-match against contact_name (case-insensitive) OR contact_address (digits/email/etc). */
12
15
  search?: string;
13
16
  cursor?: string;
14
17
  limit?: number;
15
18
  }
19
+ /**
20
+ * Janela de datas efetivamente usada na consulta.
21
+ *
22
+ * Existe porque o backend aplica um default quando o cliente nao manda datas —
23
+ * e ate a feat-127 nao contava isso a ninguem. O usuario procurava uma conversa
24
+ * fora da janela, recebia lista vazia e concluia que ela tinha sumido.
25
+ *
26
+ * `default_window_days` vem junto para o cliente rotular ("ultimos 30 dias") sem
27
+ * duplicar a constante: a regra tem UM dono, que e' o backend.
28
+ */
29
+ export interface AppliedWindow {
30
+ /** ISO. Inicio da janela consultada. */
31
+ date_from: string;
32
+ /** ISO. Fim da janela consultada. */
33
+ date_to: string;
34
+ /** true = o cliente nao mandou datas e o backend aplicou o default. */
35
+ defaulted: boolean;
36
+ /** Tamanho do default, em dias. */
37
+ default_window_days: number;
38
+ }
16
39
  export interface SearchThreadCursor {
17
40
  last_activity_ms: number;
18
41
  contact_id: string;
@@ -66,8 +89,58 @@ export interface SearchThreadsResponse {
66
89
  ok: true;
67
90
  threads: ThreadAggregate[];
68
91
  nextCursor?: string;
92
+ /** Janela realmente aplicada — mandada pelo cliente ou default do backend. */
93
+ applied_window: AppliedWindow;
94
+ /**
95
+ * Total de CONVERSAS (contatos distintos) que casam com os filtros na janela.
96
+ *
97
+ * Independente de paginacao: e' o mesmo valor em todas as paginas. Sai da
98
+ * propria query da lista (`COUNT(*) OVER ()`), sem query extra e sem bytes
99
+ * adicionais — o agregado por contato ja e' materializado inteiro antes do
100
+ * LIMIT.
101
+ */
102
+ total: number;
69
103
  stats: SearchThreadsStats;
70
104
  }
105
+ /**
106
+ * Dimensoes com contagem na busca avancada.
107
+ *
108
+ * `tag_ids` NAO esta aqui de proposito: tags nao existem no BigQuery — o filtro
109
+ * por tag resolve os contatos no Firestore ANTES da query. Facetar exigiria
110
+ * varrer leads por tag a cada mudanca de filtro, no caminho quente da tela.
111
+ */
112
+ export type SearchFacetDimension = 'status' | 'department_id' | 'attendant_type' | 'assigned_user_id' | 'closed_by_user_id' | 'close_code';
113
+ export interface SearchFacetBucket {
114
+ value: string;
115
+ /** Contagem em CONVERSAS distintas (contatos), NAO em tickets. */
116
+ count: number;
117
+ /**
118
+ * So' preenchido em `closed_by_user_id`. Hub-omni e' cross-tenant: quem
119
+ * encerra um ticket do tenant X nem sempre consta em `tenants/X/users`, entao
120
+ * o cliente nao tem como resolver esse rotulo sozinho. Nas demais dimensoes o
121
+ * cliente ja carrega o dicionario correspondente.
122
+ */
123
+ label?: string;
124
+ }
125
+ export interface SearchFacetsStats {
126
+ bq_query_id?: string;
127
+ bq_bytes_processed?: number;
128
+ duration_ms: number;
129
+ }
130
+ export interface SearchFacetsResponse {
131
+ ok: true;
132
+ /**
133
+ * Contagem por dimensao. Cada dimensao aplica TODOS os filtros ativos MENOS o
134
+ * dela propria (faceting classico) — senao marcar uma opcao zeraria todas as
135
+ * outras da mesma lista.
136
+ *
137
+ * Valor ausente = zero. O cliente que renderiza a lista de opcoes a partir de
138
+ * um dicionario deve tratar ausencia como `(0)`.
139
+ */
140
+ facets: Record<SearchFacetDimension, SearchFacetBucket[]>;
141
+ applied_window: AppliedWindow;
142
+ stats: SearchFacetsStats;
143
+ }
71
144
  export type SearchThreadsErrorCode = 'invalid_filter' | 'tag_filter_too_broad' | 'forbidden' | 'bq_error' | 'fs_error';
72
145
  export interface SearchThreadsErrorResponse {
73
146
  ok: false;
@@ -135,5 +208,7 @@ export interface TimelineResponse {
135
208
  ok: true;
136
209
  timeline: TimelineEntry[];
137
210
  nextCursor?: string;
211
+ /** Mesma janela default silenciosa da lista — ver `AppliedWindow`. */
212
+ applied_window: AppliedWindow;
138
213
  stats: TimelineStats;
139
214
  }
@@ -14,6 +14,9 @@ export interface SearchThreadsParams {
14
14
  department_ids?: string[];
15
15
  attendant_type?: SearchAttendantType;
16
16
  assigned_user_id?: string;
17
+ /** Atendente que ENCERROU algum ticket da conversa na janela. */
18
+ closed_by_user_id?: string;
19
+ close_codes?: string[];
17
20
  tag_ids?: string[];
18
21
  /** Free-text contains-match against contact_name (case-insensitive) OR contact_address (digits/email/etc). */
19
22
  search?: string;
@@ -21,6 +24,27 @@ export interface SearchThreadsParams {
21
24
  limit?: number;
22
25
  }
23
26
 
27
+ /**
28
+ * Janela de datas efetivamente usada na consulta.
29
+ *
30
+ * Existe porque o backend aplica um default quando o cliente nao manda datas —
31
+ * e ate a feat-127 nao contava isso a ninguem. O usuario procurava uma conversa
32
+ * fora da janela, recebia lista vazia e concluia que ela tinha sumido.
33
+ *
34
+ * `default_window_days` vem junto para o cliente rotular ("ultimos 30 dias") sem
35
+ * duplicar a constante: a regra tem UM dono, que e' o backend.
36
+ */
37
+ export interface AppliedWindow {
38
+ /** ISO. Inicio da janela consultada. */
39
+ date_from: string;
40
+ /** ISO. Fim da janela consultada. */
41
+ date_to: string;
42
+ /** true = o cliente nao mandou datas e o backend aplicou o default. */
43
+ defaulted: boolean;
44
+ /** Tamanho do default, em dias. */
45
+ default_window_days: number;
46
+ }
47
+
24
48
  export interface SearchThreadCursor {
25
49
  last_activity_ms: number;
26
50
  contact_id: string;
@@ -80,9 +104,71 @@ export interface SearchThreadsResponse {
80
104
  ok: true;
81
105
  threads: ThreadAggregate[];
82
106
  nextCursor?: string;
107
+ /** Janela realmente aplicada — mandada pelo cliente ou default do backend. */
108
+ applied_window: AppliedWindow;
109
+ /**
110
+ * Total de CONVERSAS (contatos distintos) que casam com os filtros na janela.
111
+ *
112
+ * Independente de paginacao: e' o mesmo valor em todas as paginas. Sai da
113
+ * propria query da lista (`COUNT(*) OVER ()`), sem query extra e sem bytes
114
+ * adicionais — o agregado por contato ja e' materializado inteiro antes do
115
+ * LIMIT.
116
+ */
117
+ total: number;
83
118
  stats: SearchThreadsStats;
84
119
  }
85
120
 
121
+ // ── Facets ──
122
+
123
+ /**
124
+ * Dimensoes com contagem na busca avancada.
125
+ *
126
+ * `tag_ids` NAO esta aqui de proposito: tags nao existem no BigQuery — o filtro
127
+ * por tag resolve os contatos no Firestore ANTES da query. Facetar exigiria
128
+ * varrer leads por tag a cada mudanca de filtro, no caminho quente da tela.
129
+ */
130
+ export type SearchFacetDimension =
131
+ | 'status'
132
+ | 'department_id'
133
+ | 'attendant_type'
134
+ | 'assigned_user_id'
135
+ | 'closed_by_user_id'
136
+ | 'close_code';
137
+
138
+ export interface SearchFacetBucket {
139
+ value: string;
140
+ /** Contagem em CONVERSAS distintas (contatos), NAO em tickets. */
141
+ count: number;
142
+ /**
143
+ * So' preenchido em `closed_by_user_id`. Hub-omni e' cross-tenant: quem
144
+ * encerra um ticket do tenant X nem sempre consta em `tenants/X/users`, entao
145
+ * o cliente nao tem como resolver esse rotulo sozinho. Nas demais dimensoes o
146
+ * cliente ja carrega o dicionario correspondente.
147
+ */
148
+ label?: string;
149
+ }
150
+
151
+ export interface SearchFacetsStats {
152
+ bq_query_id?: string;
153
+ bq_bytes_processed?: number;
154
+ duration_ms: number;
155
+ }
156
+
157
+ export interface SearchFacetsResponse {
158
+ ok: true;
159
+ /**
160
+ * Contagem por dimensao. Cada dimensao aplica TODOS os filtros ativos MENOS o
161
+ * dela propria (faceting classico) — senao marcar uma opcao zeraria todas as
162
+ * outras da mesma lista.
163
+ *
164
+ * Valor ausente = zero. O cliente que renderiza a lista de opcoes a partir de
165
+ * um dicionario deve tratar ausencia como `(0)`.
166
+ */
167
+ facets: Record<SearchFacetDimension, SearchFacetBucket[]>;
168
+ applied_window: AppliedWindow;
169
+ stats: SearchFacetsStats;
170
+ }
171
+
86
172
  export type SearchThreadsErrorCode =
87
173
  | 'invalid_filter'
88
174
  | 'tag_filter_too_broad'
@@ -178,5 +264,7 @@ export interface TimelineResponse {
178
264
  ok: true;
179
265
  timeline: TimelineEntry[];
180
266
  nextCursor?: string;
267
+ /** Mesma janela default silenciosa da lista — ver `AppliedWindow`. */
268
+ applied_window: AppliedWindow;
181
269
  stats: TimelineStats;
182
270
  }
@@ -7,7 +7,37 @@ import type { IFireGlobalDoc } from '../../shared';
7
7
  */
8
8
  export type NexFinopsContractStatus = 'draft' | 'active' | 'cancellation_requested' | 'inactive' | 'ended' | 'canceled';
9
9
  export type NexFinopsContractRecurrence = 'one_time' | 'monthly';
10
- export type NexFinopsPaymentMethod = 'pix' | 'boleto' | 'payment_link';
10
+ /**
11
+ * `card_subscription` entra na feat-131 para convergir com
12
+ * `NexFinopsProposalPaymentMethod`: o que a proposta aceita é o que o contrato
13
+ * registra. `pix` continua porque o operador ainda lança cobrança avulsa por pix.
14
+ */
15
+ export type NexFinopsPaymentMethod = 'pix' | 'boleto' | 'payment_link' | 'card_subscription';
16
+ /** Status da assinatura no Asaas. */
17
+ export type NexFinopsAsaasSubscriptionStatus = 'ACTIVE' | 'EXPIRED' | 'INACTIVE';
18
+ /**
19
+ * Vínculo contrato ↔ assinatura Asaas (D2). Escrito uma vez, na confirmação do
20
+ * primeiro pagamento, a partir de `GET /v3/subscriptions/{id}`.
21
+ *
22
+ * PCI: o checkout é hospedado pelo Asaas (SAQ-A) e o cartão nunca toca este
23
+ * backend. Por isso aqui só cabem os 4 últimos dígitos e a bandeira — número
24
+ * completo, CCV, trilha ou token de cartão NÃO têm campo neste tipo e não devem
25
+ * ganhar um.
26
+ */
27
+ export interface INexFinopsContractAsaasInfo {
28
+ customer_id?: string | null;
29
+ subscription_id?: string | null;
30
+ subscription_status?: NexFinopsAsaasSubscriptionStatus | null;
31
+ cycle?: string | null;
32
+ value?: number | null;
33
+ /** Data civil `YYYY-MM-DD`, igual ao resto do finops. */
34
+ next_due_date?: string | null;
35
+ card_last4?: string | null;
36
+ card_brand?: string | null;
37
+ /** Sessão de checkout hospedado que originou a assinatura. */
38
+ checkout_id?: string | null;
39
+ env?: 'sandbox' | 'production' | null;
40
+ }
11
41
  export interface INexFinopsContractServiceItem {
12
42
  category: string;
13
43
  description: string;
@@ -29,6 +59,18 @@ export interface INexFinopsContract extends IFireGlobalDoc {
29
59
  total_amount: number;
30
60
  currency: 'BRL';
31
61
  notes?: string | null;
62
+ /** Doc id (= `short_code`) da jornada que originou este contrato. */
63
+ journey_ref?: string | null;
64
+ /** Path Firestore da proposta que originou este contrato. */
65
+ proposal_ref?: string | null;
66
+ /**
67
+ * D5 — contrato fechado pelo próprio cliente no site (`origem === 'site-hm'`)
68
+ * nasce com direito a estorno; venda assistida, não. Default `false`.
69
+ */
70
+ refund_eligible?: boolean | null;
71
+ /** Método com que o primeiro pagamento foi feito. `accepted_payment_methods` é a oferta; este é o fato. */
72
+ payment_method?: NexFinopsPaymentMethod | null;
73
+ asaas?: INexFinopsContractAsaasInfo | null;
32
74
  }
33
75
  export declare const NEX_FINOPS_CONTRACT_STATUS_TRANSITIONS: Record<NexFinopsContractStatus, NexFinopsContractStatus[]>;
34
76
  /**
@@ -10,7 +10,40 @@ import type { IFireGlobalDoc } from '../../shared';
10
10
  */
11
11
  export type NexFinopsContractStatus = 'draft' | 'active' | 'cancellation_requested' | 'inactive' | 'ended' | 'canceled';
12
12
  export type NexFinopsContractRecurrence = 'one_time' | 'monthly';
13
- export type NexFinopsPaymentMethod = 'pix' | 'boleto' | 'payment_link';
13
+
14
+ /**
15
+ * `card_subscription` entra na feat-131 para convergir com
16
+ * `NexFinopsProposalPaymentMethod`: o que a proposta aceita é o que o contrato
17
+ * registra. `pix` continua porque o operador ainda lança cobrança avulsa por pix.
18
+ */
19
+ export type NexFinopsPaymentMethod = 'pix' | 'boleto' | 'payment_link' | 'card_subscription';
20
+
21
+ /** Status da assinatura no Asaas. */
22
+ export type NexFinopsAsaasSubscriptionStatus = 'ACTIVE' | 'EXPIRED' | 'INACTIVE';
23
+
24
+ /**
25
+ * Vínculo contrato ↔ assinatura Asaas (D2). Escrito uma vez, na confirmação do
26
+ * primeiro pagamento, a partir de `GET /v3/subscriptions/{id}`.
27
+ *
28
+ * PCI: o checkout é hospedado pelo Asaas (SAQ-A) e o cartão nunca toca este
29
+ * backend. Por isso aqui só cabem os 4 últimos dígitos e a bandeira — número
30
+ * completo, CCV, trilha ou token de cartão NÃO têm campo neste tipo e não devem
31
+ * ganhar um.
32
+ */
33
+ export interface INexFinopsContractAsaasInfo {
34
+ customer_id?: string | null;
35
+ subscription_id?: string | null;
36
+ subscription_status?: NexFinopsAsaasSubscriptionStatus | null;
37
+ cycle?: string | null;
38
+ value?: number | null;
39
+ /** Data civil `YYYY-MM-DD`, igual ao resto do finops. */
40
+ next_due_date?: string | null;
41
+ card_last4?: string | null;
42
+ card_brand?: string | null;
43
+ /** Sessão de checkout hospedado que originou a assinatura. */
44
+ checkout_id?: string | null;
45
+ env?: 'sandbox' | 'production' | null;
46
+ }
14
47
 
15
48
  // ── Service Item ──
16
49
 
@@ -55,6 +88,24 @@ export interface INexFinopsContract extends IFireGlobalDoc {
55
88
 
56
89
  // Observações
57
90
  notes?: string | null;
91
+
92
+ // ── Origem na jornada de contratação (feat-130) ──
93
+
94
+ /** Doc id (= `short_code`) da jornada que originou este contrato. */
95
+ journey_ref?: string | null;
96
+ /** Path Firestore da proposta que originou este contrato. */
97
+ proposal_ref?: string | null;
98
+ /**
99
+ * D5 — contrato fechado pelo próprio cliente no site (`origem === 'site-hm'`)
100
+ * nasce com direito a estorno; venda assistida, não. Default `false`.
101
+ */
102
+ refund_eligible?: boolean | null;
103
+
104
+ // ── Pagamento efetivo (feat-131) ──
105
+
106
+ /** Método com que o primeiro pagamento foi feito. `accepted_payment_methods` é a oferta; este é o fato. */
107
+ payment_method?: NexFinopsPaymentMethod | null;
108
+ asaas?: INexFinopsContractAsaasInfo | null;
58
109
  }
59
110
 
60
111
  // ── Status transitions ──