@voyantjs/crm 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/LICENSE +109 -0
  2. package/README.md +47 -0
  3. package/dist/booking-extension.d.ts +123 -0
  4. package/dist/booking-extension.d.ts.map +1 -0
  5. package/dist/booking-extension.js +86 -0
  6. package/dist/index.d.ts +14 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +29 -0
  9. package/dist/routes/accounts.d.ts +1203 -0
  10. package/dist/routes/accounts.d.ts.map +1 -0
  11. package/dist/routes/accounts.js +226 -0
  12. package/dist/routes/activities.d.ts +299 -0
  13. package/dist/routes/activities.d.ts.map +1 -0
  14. package/dist/routes/activities.js +61 -0
  15. package/dist/routes/custom-fields.d.ts +256 -0
  16. package/dist/routes/custom-fields.d.ts.map +1 -0
  17. package/dist/routes/custom-fields.js +46 -0
  18. package/dist/routes/index.d.ts +2671 -0
  19. package/dist/routes/index.d.ts.map +1 -0
  20. package/dist/routes/index.js +14 -0
  21. package/dist/routes/opportunities.d.ts +387 -0
  22. package/dist/routes/opportunities.d.ts.map +1 -0
  23. package/dist/routes/opportunities.js +69 -0
  24. package/dist/routes/pipelines.d.ts +292 -0
  25. package/dist/routes/pipelines.d.ts.map +1 -0
  26. package/dist/routes/pipelines.js +58 -0
  27. package/dist/routes/quotes.d.ts +283 -0
  28. package/dist/routes/quotes.d.ts.map +1 -0
  29. package/dist/routes/quotes.js +51 -0
  30. package/dist/schema.d.ts +3478 -0
  31. package/dist/schema.d.ts.map +1 -0
  32. package/dist/schema.js +515 -0
  33. package/dist/service/accounts.d.ts +982 -0
  34. package/dist/service/accounts.d.ts.map +1 -0
  35. package/dist/service/accounts.js +509 -0
  36. package/dist/service/activities.d.ts +486 -0
  37. package/dist/service/activities.d.ts.map +1 -0
  38. package/dist/service/activities.js +114 -0
  39. package/dist/service/custom-fields.d.ts +118 -0
  40. package/dist/service/custom-fields.d.ts.map +1 -0
  41. package/dist/service/custom-fields.js +88 -0
  42. package/dist/service/helpers.d.ts +22 -0
  43. package/dist/service/helpers.d.ts.map +1 -0
  44. package/dist/service/helpers.js +39 -0
  45. package/dist/service/index.d.ts +3329 -0
  46. package/dist/service/index.d.ts.map +1 -0
  47. package/dist/service/index.js +14 -0
  48. package/dist/service/opportunities.d.ts +822 -0
  49. package/dist/service/opportunities.d.ts.map +1 -0
  50. package/dist/service/opportunities.js +117 -0
  51. package/dist/service/pipelines.d.ts +113 -0
  52. package/dist/service/pipelines.d.ts.map +1 -0
  53. package/dist/service/pipelines.js +68 -0
  54. package/dist/service/quotes.d.ts +494 -0
  55. package/dist/service/quotes.d.ts.map +1 -0
  56. package/dist/service/quotes.js +69 -0
  57. package/dist/validation.d.ts +860 -0
  58. package/dist/validation.d.ts.map +1 -0
  59. package/dist/validation.js +315 -0
  60. package/package.json +56 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/dist/schema.js ADDED
@@ -0,0 +1,515 @@
1
+ import { typeId, typeIdRef } from "@voyantjs/db/lib/typeid-column";
2
+ import { relations } from "drizzle-orm";
3
+ import { boolean, date, index, integer, jsonb, pgEnum, pgTable, text, timestamp, uniqueIndex, } from "drizzle-orm/pg-core";
4
+ export const entityTypeEnum = pgEnum("entity_type", [
5
+ "organization",
6
+ "person",
7
+ "opportunity",
8
+ "quote",
9
+ "activity",
10
+ ]);
11
+ export const relationTypeEnum = pgEnum("relation_type", ["client", "partner", "supplier", "other"]);
12
+ export const communicationChannelEnum = pgEnum("communication_channel", [
13
+ "email",
14
+ "phone",
15
+ "whatsapp",
16
+ "sms",
17
+ "meeting",
18
+ "other",
19
+ ]);
20
+ export const communicationDirectionEnum = pgEnum("communication_direction", ["inbound", "outbound"]);
21
+ export const recordStatusEnum = pgEnum("record_status", ["active", "inactive", "archived"]);
22
+ export const opportunityStatusEnum = pgEnum("opportunity_status", [
23
+ "open",
24
+ "won",
25
+ "lost",
26
+ "archived",
27
+ ]);
28
+ export const quoteStatusEnum = pgEnum("quote_status", [
29
+ "draft",
30
+ "sent",
31
+ "accepted",
32
+ "expired",
33
+ "rejected",
34
+ "archived",
35
+ ]);
36
+ export const activityTypeEnum = pgEnum("activity_type", [
37
+ "call",
38
+ "email",
39
+ "meeting",
40
+ "task",
41
+ "follow_up",
42
+ "note",
43
+ ]);
44
+ export const activityStatusEnum = pgEnum("activity_status", ["planned", "done", "cancelled"]);
45
+ export const activityLinkRoleEnum = pgEnum("activity_link_role", ["primary", "related"]);
46
+ export const participantRoleEnum = pgEnum("participant_role", [
47
+ "traveler",
48
+ "booker",
49
+ "decision_maker",
50
+ "finance",
51
+ "other",
52
+ ]);
53
+ export const customFieldTypeEnum = pgEnum("custom_field_type", [
54
+ "varchar",
55
+ "text",
56
+ "double",
57
+ "monetary",
58
+ "date",
59
+ "boolean",
60
+ "enum",
61
+ "set",
62
+ "json",
63
+ "address",
64
+ "phone",
65
+ ]);
66
+ export const organizations = pgTable("organizations", {
67
+ id: typeId("organizations"),
68
+ name: text("name").notNull(),
69
+ legalName: text("legal_name"),
70
+ website: text("website"),
71
+ industry: text("industry"),
72
+ relation: relationTypeEnum("relation"),
73
+ ownerId: text("owner_id"),
74
+ defaultCurrency: text("default_currency"),
75
+ preferredLanguage: text("preferred_language"),
76
+ paymentTerms: integer("payment_terms"),
77
+ status: recordStatusEnum("status").notNull().default("active"),
78
+ source: text("source"),
79
+ sourceRef: text("source_ref"),
80
+ tags: jsonb("tags").$type().notNull().default([]),
81
+ notes: text("notes"),
82
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
83
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
84
+ archivedAt: timestamp("archived_at", { withTimezone: true }),
85
+ }, (table) => [
86
+ index("idx_organizations_name").on(table.name),
87
+ index("idx_organizations_owner").on(table.ownerId),
88
+ index("idx_organizations_status").on(table.status),
89
+ ]);
90
+ export const people = pgTable("people", {
91
+ id: typeId("people"),
92
+ organizationId: typeIdRef("organization_id").references(() => organizations.id, {
93
+ onDelete: "set null",
94
+ }),
95
+ firstName: text("first_name").notNull(),
96
+ lastName: text("last_name").notNull(),
97
+ jobTitle: text("job_title"),
98
+ relation: relationTypeEnum("relation"),
99
+ preferredLanguage: text("preferred_language"),
100
+ preferredCurrency: text("preferred_currency"),
101
+ ownerId: text("owner_id"),
102
+ status: recordStatusEnum("status").notNull().default("active"),
103
+ source: text("source"),
104
+ sourceRef: text("source_ref"),
105
+ tags: jsonb("tags").$type().notNull().default([]),
106
+ birthday: date("birthday"),
107
+ notes: text("notes"),
108
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
109
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
110
+ archivedAt: timestamp("archived_at", { withTimezone: true }),
111
+ }, (table) => [
112
+ index("idx_people_org").on(table.organizationId),
113
+ index("idx_people_owner").on(table.ownerId),
114
+ index("idx_people_status").on(table.status),
115
+ index("idx_people_name").on(table.firstName, table.lastName),
116
+ ]);
117
+ export const pipelines = pgTable("pipelines", {
118
+ id: typeId("pipelines"),
119
+ entityType: entityTypeEnum("entity_type").notNull().default("opportunity"),
120
+ name: text("name").notNull(),
121
+ isDefault: boolean("is_default").notNull().default(false),
122
+ sortOrder: integer("sort_order").notNull().default(0),
123
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
124
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
125
+ }, (table) => [
126
+ index("idx_pipelines_entity").on(table.entityType),
127
+ uniqueIndex("uidx_pipelines_entity_name").on(table.entityType, table.name),
128
+ ]);
129
+ export const stages = pgTable("stages", {
130
+ id: typeId("stages"),
131
+ pipelineId: typeIdRef("pipeline_id")
132
+ .notNull()
133
+ .references(() => pipelines.id, { onDelete: "cascade" }),
134
+ name: text("name").notNull(),
135
+ sortOrder: integer("sort_order").notNull().default(0),
136
+ probability: integer("probability"),
137
+ isClosed: boolean("is_closed").notNull().default(false),
138
+ isWon: boolean("is_won").notNull().default(false),
139
+ isLost: boolean("is_lost").notNull().default(false),
140
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
141
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
142
+ }, (table) => [
143
+ index("idx_stages_pipeline").on(table.pipelineId),
144
+ uniqueIndex("uidx_stages_pipeline_name").on(table.pipelineId, table.name),
145
+ ]);
146
+ export const opportunities = pgTable("opportunities", {
147
+ id: typeId("opportunities"),
148
+ title: text("title").notNull(),
149
+ personId: typeIdRef("person_id").references(() => people.id, { onDelete: "set null" }),
150
+ organizationId: typeIdRef("organization_id").references(() => organizations.id, {
151
+ onDelete: "set null",
152
+ }),
153
+ pipelineId: typeIdRef("pipeline_id")
154
+ .notNull()
155
+ .references(() => pipelines.id, { onDelete: "restrict" }),
156
+ stageId: typeIdRef("stage_id")
157
+ .notNull()
158
+ .references(() => stages.id, { onDelete: "restrict" }),
159
+ ownerId: text("owner_id"),
160
+ status: opportunityStatusEnum("status").notNull().default("open"),
161
+ valueAmountCents: integer("value_amount_cents"),
162
+ valueCurrency: text("value_currency"),
163
+ expectedCloseDate: date("expected_close_date"),
164
+ source: text("source"),
165
+ sourceRef: text("source_ref"),
166
+ lostReason: text("lost_reason"),
167
+ tags: jsonb("tags").$type().notNull().default([]),
168
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
169
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
170
+ stageChangedAt: timestamp("stage_changed_at", { withTimezone: true }).notNull().defaultNow(),
171
+ closedAt: timestamp("closed_at", { withTimezone: true }),
172
+ }, (table) => [
173
+ index("idx_opportunities_person").on(table.personId),
174
+ index("idx_opportunities_org").on(table.organizationId),
175
+ index("idx_opportunities_pipeline").on(table.pipelineId),
176
+ index("idx_opportunities_stage").on(table.stageId),
177
+ index("idx_opportunities_owner").on(table.ownerId),
178
+ index("idx_opportunities_status").on(table.status),
179
+ ]);
180
+ export const opportunityParticipants = pgTable("opportunity_participants", {
181
+ id: typeId("opportunity_participants"),
182
+ opportunityId: typeIdRef("opportunity_id")
183
+ .notNull()
184
+ .references(() => opportunities.id, { onDelete: "cascade" }),
185
+ personId: typeIdRef("person_id")
186
+ .notNull()
187
+ .references(() => people.id, { onDelete: "cascade" }),
188
+ role: participantRoleEnum("role").notNull().default("other"),
189
+ isPrimary: boolean("is_primary").notNull().default(false),
190
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
191
+ }, (table) => [
192
+ index("idx_opportunity_participants_opportunity").on(table.opportunityId),
193
+ index("idx_opportunity_participants_person").on(table.personId),
194
+ uniqueIndex("uidx_opportunity_participants_unique").on(table.opportunityId, table.personId),
195
+ ]);
196
+ export const opportunityProducts = pgTable("opportunity_products", {
197
+ id: typeId("opportunity_products"),
198
+ opportunityId: typeIdRef("opportunity_id")
199
+ .notNull()
200
+ .references(() => opportunities.id, { onDelete: "cascade" }),
201
+ productId: text("product_id"),
202
+ supplierServiceId: text("supplier_service_id"),
203
+ nameSnapshot: text("name_snapshot").notNull(),
204
+ description: text("description"),
205
+ quantity: integer("quantity").notNull().default(1),
206
+ unitPriceAmountCents: integer("unit_price_amount_cents"),
207
+ costAmountCents: integer("cost_amount_cents"),
208
+ currency: text("currency"),
209
+ discountAmountCents: integer("discount_amount_cents"),
210
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
211
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
212
+ }, (table) => [
213
+ index("idx_opportunity_products_opportunity").on(table.opportunityId),
214
+ index("idx_opportunity_products_product").on(table.productId),
215
+ index("idx_opportunity_products_supplier_service").on(table.supplierServiceId),
216
+ ]);
217
+ export const quotes = pgTable("quotes", {
218
+ id: typeId("quotes"),
219
+ opportunityId: typeIdRef("opportunity_id")
220
+ .notNull()
221
+ .references(() => opportunities.id, { onDelete: "cascade" }),
222
+ status: quoteStatusEnum("status").notNull().default("draft"),
223
+ validUntil: date("valid_until"),
224
+ currency: text("currency").notNull(),
225
+ subtotalAmountCents: integer("subtotal_amount_cents").notNull().default(0),
226
+ taxAmountCents: integer("tax_amount_cents").notNull().default(0),
227
+ totalAmountCents: integer("total_amount_cents").notNull().default(0),
228
+ notes: text("notes"),
229
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
230
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
231
+ archivedAt: timestamp("archived_at", { withTimezone: true }),
232
+ }, (table) => [
233
+ index("idx_quotes_opportunity").on(table.opportunityId),
234
+ index("idx_quotes_status").on(table.status),
235
+ ]);
236
+ export const quoteLines = pgTable("quote_lines", {
237
+ id: typeId("quote_lines"),
238
+ quoteId: typeIdRef("quote_id")
239
+ .notNull()
240
+ .references(() => quotes.id, { onDelete: "cascade" }),
241
+ productId: text("product_id"),
242
+ supplierServiceId: text("supplier_service_id"),
243
+ description: text("description").notNull(),
244
+ quantity: integer("quantity").notNull().default(1),
245
+ unitPriceAmountCents: integer("unit_price_amount_cents").notNull().default(0),
246
+ totalAmountCents: integer("total_amount_cents").notNull().default(0),
247
+ currency: text("currency").notNull(),
248
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
249
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
250
+ }, (table) => [
251
+ index("idx_quote_lines_quote").on(table.quoteId),
252
+ index("idx_quote_lines_product").on(table.productId),
253
+ index("idx_quote_lines_supplier_service").on(table.supplierServiceId),
254
+ ]);
255
+ export const activities = pgTable("activities", {
256
+ id: typeId("activities"),
257
+ subject: text("subject").notNull(),
258
+ type: activityTypeEnum("type").notNull(),
259
+ ownerId: text("owner_id"),
260
+ status: activityStatusEnum("status").notNull().default("planned"),
261
+ dueAt: timestamp("due_at", { withTimezone: true }),
262
+ completedAt: timestamp("completed_at", { withTimezone: true }),
263
+ location: text("location"),
264
+ description: text("description"),
265
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
266
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
267
+ }, (table) => [
268
+ index("idx_activities_owner").on(table.ownerId),
269
+ index("idx_activities_status").on(table.status),
270
+ index("idx_activities_type").on(table.type),
271
+ ]);
272
+ export const activityLinks = pgTable("activity_links", {
273
+ id: typeId("activity_links"),
274
+ activityId: typeIdRef("activity_id")
275
+ .notNull()
276
+ .references(() => activities.id, { onDelete: "cascade" }),
277
+ entityType: entityTypeEnum("entity_type").notNull(),
278
+ entityId: text("entity_id").notNull(),
279
+ role: activityLinkRoleEnum("role").notNull().default("related"),
280
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
281
+ }, (table) => [
282
+ index("idx_activity_links_activity").on(table.activityId),
283
+ index("idx_activity_links_entity").on(table.entityType, table.entityId),
284
+ ]);
285
+ export const activityParticipants = pgTable("activity_participants", {
286
+ id: typeId("activity_participants"),
287
+ activityId: typeIdRef("activity_id")
288
+ .notNull()
289
+ .references(() => activities.id, { onDelete: "cascade" }),
290
+ personId: typeIdRef("person_id")
291
+ .notNull()
292
+ .references(() => people.id, { onDelete: "cascade" }),
293
+ isPrimary: boolean("is_primary").notNull().default(false),
294
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
295
+ }, (table) => [
296
+ index("idx_activity_participants_activity").on(table.activityId),
297
+ uniqueIndex("uidx_activity_participants_unique").on(table.activityId, table.personId),
298
+ ]);
299
+ export const customFieldDefinitions = pgTable("custom_field_definitions", {
300
+ id: typeId("custom_field_definitions"),
301
+ entityType: entityTypeEnum("entity_type").notNull(),
302
+ key: text("key").notNull(),
303
+ label: text("label").notNull(),
304
+ fieldType: customFieldTypeEnum("field_type").notNull(),
305
+ isRequired: boolean("is_required").notNull().default(false),
306
+ isSearchable: boolean("is_searchable").notNull().default(false),
307
+ options: jsonb("options").$type(),
308
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
309
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
310
+ }, (table) => [
311
+ index("idx_custom_field_definitions_entity").on(table.entityType),
312
+ uniqueIndex("uidx_custom_field_definitions_key").on(table.entityType, table.key),
313
+ ]);
314
+ export const customFieldValues = pgTable("custom_field_values", {
315
+ id: typeId("custom_field_values"),
316
+ definitionId: typeIdRef("definition_id")
317
+ .notNull()
318
+ .references(() => customFieldDefinitions.id, { onDelete: "cascade" }),
319
+ entityType: entityTypeEnum("entity_type").notNull(),
320
+ entityId: text("entity_id").notNull(),
321
+ textValue: text("text_value"),
322
+ numberValue: integer("number_value"),
323
+ dateValue: date("date_value"),
324
+ booleanValue: boolean("boolean_value"),
325
+ monetaryValueCents: integer("monetary_value_cents"),
326
+ currencyCode: text("currency_code"),
327
+ jsonValue: jsonb("json_value").$type(),
328
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
329
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
330
+ }, (table) => [
331
+ index("idx_custom_field_values_entity").on(table.entityType, table.entityId),
332
+ uniqueIndex("uidx_custom_field_values_unique").on(table.definitionId, table.entityType, table.entityId),
333
+ ]);
334
+ // ---------- person_notes ----------
335
+ export const personNotes = pgTable("person_notes", {
336
+ id: typeId("person_notes"),
337
+ personId: typeIdRef("person_id")
338
+ .notNull()
339
+ .references(() => people.id, { onDelete: "cascade" }),
340
+ authorId: text("author_id").notNull(),
341
+ content: text("content").notNull(),
342
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
343
+ }, (table) => [index("idx_person_notes_person").on(table.personId)]);
344
+ // ---------- organization_notes ----------
345
+ export const organizationNotes = pgTable("organization_notes", {
346
+ id: typeId("organization_notes"),
347
+ organizationId: typeIdRef("organization_id")
348
+ .notNull()
349
+ .references(() => organizations.id, { onDelete: "cascade" }),
350
+ authorId: text("author_id").notNull(),
351
+ content: text("content").notNull(),
352
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
353
+ }, (table) => [index("idx_organization_notes_org").on(table.organizationId)]);
354
+ // ---------- communication_log ----------
355
+ export const communicationLog = pgTable("communication_log", {
356
+ id: typeId("communication_log"),
357
+ personId: typeIdRef("person_id")
358
+ .notNull()
359
+ .references(() => people.id, { onDelete: "cascade" }),
360
+ organizationId: typeIdRef("organization_id").references(() => organizations.id, {
361
+ onDelete: "set null",
362
+ }),
363
+ channel: communicationChannelEnum("channel").notNull(),
364
+ direction: communicationDirectionEnum("direction").notNull(),
365
+ subject: text("subject"),
366
+ content: text("content"),
367
+ sentAt: timestamp("sent_at", { withTimezone: true }),
368
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
369
+ }, (table) => [
370
+ index("idx_communication_log_person").on(table.personId),
371
+ index("idx_communication_log_org").on(table.organizationId),
372
+ index("idx_communication_log_channel").on(table.channel),
373
+ ]);
374
+ // ---------- segments ----------
375
+ export const segments = pgTable("segments", {
376
+ id: typeId("segments"),
377
+ name: text("name").notNull(),
378
+ description: text("description"),
379
+ conditions: jsonb("conditions").$type(),
380
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
381
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
382
+ });
383
+ // ---------- segment_members ----------
384
+ export const segmentMembers = pgTable("segment_members", {
385
+ id: typeId("segment_members"),
386
+ segmentId: typeIdRef("segment_id")
387
+ .notNull()
388
+ .references(() => segments.id, { onDelete: "cascade" }),
389
+ personId: typeIdRef("person_id")
390
+ .notNull()
391
+ .references(() => people.id, { onDelete: "cascade" }),
392
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
393
+ }, (table) => [
394
+ index("idx_segment_members_segment").on(table.segmentId),
395
+ index("idx_segment_members_person").on(table.personId),
396
+ ]);
397
+ export const organizationsRelations = relations(organizations, ({ many }) => ({
398
+ people: many(people),
399
+ opportunities: many(opportunities),
400
+ notes: many(organizationNotes),
401
+ communications: many(communicationLog),
402
+ }));
403
+ export const peopleRelations = relations(people, ({ one, many }) => ({
404
+ organization: one(organizations, {
405
+ fields: [people.organizationId],
406
+ references: [organizations.id],
407
+ }),
408
+ opportunities: many(opportunities),
409
+ activityParticipants: many(activityParticipants),
410
+ opportunityParticipants: many(opportunityParticipants),
411
+ notes: many(personNotes),
412
+ communications: many(communicationLog),
413
+ segmentMemberships: many(segmentMembers),
414
+ }));
415
+ export const pipelinesRelations = relations(pipelines, ({ many }) => ({
416
+ stages: many(stages),
417
+ opportunities: many(opportunities),
418
+ }));
419
+ export const stagesRelations = relations(stages, ({ one, many }) => ({
420
+ pipeline: one(pipelines, { fields: [stages.pipelineId], references: [pipelines.id] }),
421
+ opportunities: many(opportunities),
422
+ }));
423
+ export const opportunitiesRelations = relations(opportunities, ({ one, many }) => ({
424
+ person: one(people, { fields: [opportunities.personId], references: [people.id] }),
425
+ organization: one(organizations, {
426
+ fields: [opportunities.organizationId],
427
+ references: [organizations.id],
428
+ }),
429
+ pipeline: one(pipelines, {
430
+ fields: [opportunities.pipelineId],
431
+ references: [pipelines.id],
432
+ }),
433
+ stage: one(stages, { fields: [opportunities.stageId], references: [stages.id] }),
434
+ participants: many(opportunityParticipants),
435
+ products: many(opportunityProducts),
436
+ quotes: many(quotes),
437
+ }));
438
+ export const opportunityParticipantsRelations = relations(opportunityParticipants, ({ one }) => ({
439
+ opportunity: one(opportunities, {
440
+ fields: [opportunityParticipants.opportunityId],
441
+ references: [opportunities.id],
442
+ }),
443
+ person: one(people, {
444
+ fields: [opportunityParticipants.personId],
445
+ references: [people.id],
446
+ }),
447
+ }));
448
+ export const opportunityProductsRelations = relations(opportunityProducts, ({ one }) => ({
449
+ opportunity: one(opportunities, {
450
+ fields: [opportunityProducts.opportunityId],
451
+ references: [opportunities.id],
452
+ }),
453
+ }));
454
+ export const quotesRelations = relations(quotes, ({ one, many }) => ({
455
+ opportunity: one(opportunities, {
456
+ fields: [quotes.opportunityId],
457
+ references: [opportunities.id],
458
+ }),
459
+ lines: many(quoteLines),
460
+ }));
461
+ export const quoteLinesRelations = relations(quoteLines, ({ one }) => ({
462
+ quote: one(quotes, { fields: [quoteLines.quoteId], references: [quotes.id] }),
463
+ }));
464
+ export const activitiesRelations = relations(activities, ({ many }) => ({
465
+ links: many(activityLinks),
466
+ participants: many(activityParticipants),
467
+ }));
468
+ export const activityLinksRelations = relations(activityLinks, ({ one }) => ({
469
+ activity: one(activities, {
470
+ fields: [activityLinks.activityId],
471
+ references: [activities.id],
472
+ }),
473
+ }));
474
+ export const activityParticipantsRelations = relations(activityParticipants, ({ one }) => ({
475
+ activity: one(activities, {
476
+ fields: [activityParticipants.activityId],
477
+ references: [activities.id],
478
+ }),
479
+ person: one(people, {
480
+ fields: [activityParticipants.personId],
481
+ references: [people.id],
482
+ }),
483
+ }));
484
+ export const customFieldDefinitionsRelations = relations(customFieldDefinitions, ({ many }) => ({
485
+ values: many(customFieldValues),
486
+ }));
487
+ export const customFieldValuesRelations = relations(customFieldValues, ({ one }) => ({
488
+ definition: one(customFieldDefinitions, {
489
+ fields: [customFieldValues.definitionId],
490
+ references: [customFieldDefinitions.id],
491
+ }),
492
+ }));
493
+ export const personNotesRelations = relations(personNotes, ({ one }) => ({
494
+ person: one(people, { fields: [personNotes.personId], references: [people.id] }),
495
+ }));
496
+ export const organizationNotesRelations = relations(organizationNotes, ({ one }) => ({
497
+ organization: one(organizations, {
498
+ fields: [organizationNotes.organizationId],
499
+ references: [organizations.id],
500
+ }),
501
+ }));
502
+ export const communicationLogRelations = relations(communicationLog, ({ one }) => ({
503
+ person: one(people, { fields: [communicationLog.personId], references: [people.id] }),
504
+ organization: one(organizations, {
505
+ fields: [communicationLog.organizationId],
506
+ references: [organizations.id],
507
+ }),
508
+ }));
509
+ export const segmentsRelations = relations(segments, ({ many }) => ({
510
+ members: many(segmentMembers),
511
+ }));
512
+ export const segmentMembersRelations = relations(segmentMembers, ({ one }) => ({
513
+ segment: one(segments, { fields: [segmentMembers.segmentId], references: [segments.id] }),
514
+ person: one(people, { fields: [segmentMembers.personId], references: [people.id] }),
515
+ }));