@voyantjs/crm 0.106.1 → 0.107.1

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 (51) hide show
  1. package/README.md +3 -3
  2. package/dist/booking-extension.d.ts +7 -7
  3. package/dist/booking-extension.d.ts.map +1 -1
  4. package/dist/booking-extension.js +8 -5
  5. package/dist/index.d.ts +5 -3
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +3 -2
  8. package/dist/routes/activities.d.ts +2 -2
  9. package/dist/routes/custom-fields.d.ts +6 -6
  10. package/dist/routes/index.d.ts +518 -51
  11. package/dist/routes/index.d.ts.map +1 -1
  12. package/dist/routes/index.js +2 -2
  13. package/dist/routes/pipelines.d.ts +4 -4
  14. package/dist/routes/quote-versions.d.ts +746 -0
  15. package/dist/routes/quote-versions.d.ts.map +1 -0
  16. package/dist/routes/quote-versions.js +175 -0
  17. package/dist/routes/quotes.d.ts +161 -53
  18. package/dist/routes/quotes.d.ts.map +1 -1
  19. package/dist/routes/quotes.js +29 -11
  20. package/dist/schema-activities.d.ts +6 -6
  21. package/dist/schema-relations.d.ts +19 -18
  22. package/dist/schema-relations.d.ts.map +1 -1
  23. package/dist/schema-relations.js +38 -31
  24. package/dist/schema-sales.d.ts +206 -87
  25. package/dist/schema-sales.d.ts.map +1 -1
  26. package/dist/schema-sales.js +62 -50
  27. package/dist/schema-shared.d.ts +3 -3
  28. package/dist/schema-shared.d.ts.map +1 -1
  29. package/dist/schema-shared.js +5 -16
  30. package/dist/schema-signals.d.ts +1 -1
  31. package/dist/schema-signals.js +1 -1
  32. package/dist/service/accounts-merge.js +10 -10
  33. package/dist/service/activities.d.ts +6 -6
  34. package/dist/service/custom-fields.d.ts +6 -6
  35. package/dist/service/index.d.ts +338 -139
  36. package/dist/service/index.d.ts.map +1 -1
  37. package/dist/service/index.js +2 -2
  38. package/dist/service/pipelines.d.ts +4 -4
  39. package/dist/service/quote-versions.d.ts +674 -0
  40. package/dist/service/quote-versions.d.ts.map +1 -0
  41. package/dist/service/quote-versions.js +399 -0
  42. package/dist/service/quotes.d.ts +426 -94
  43. package/dist/service/quotes.d.ts.map +1 -1
  44. package/dist/service/quotes.js +63 -22
  45. package/package.json +7 -7
  46. package/dist/routes/opportunities.d.ts +0 -387
  47. package/dist/routes/opportunities.d.ts.map +0 -1
  48. package/dist/routes/opportunities.js +0 -70
  49. package/dist/service/opportunities.d.ts +0 -822
  50. package/dist/service/opportunities.d.ts.map +0 -1
  51. package/dist/service/opportunities.js +0 -117
@@ -1 +1 @@
1
- {"version":3,"file":"schema-sales.d.ts","sourceRoot":"","sources":["../src/schema-sales.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema-sales.d.ts","sourceRoot":"","sources":["../src/schema-sales.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import { typeId, typeIdRef } from "@voyantjs/db/lib/typeid-column";
2
2
  import { boolean, date, index, integer, jsonb, pgTable, text, timestamp, uniqueIndex, } from "drizzle-orm/pg-core";
3
3
  import { organizations, people } from "./schema-accounts.js";
4
- import { entityTypeEnum, opportunityStatusEnum, participantRoleEnum, quoteStatusEnum, } from "./schema-shared.js";
4
+ import { entityTypeEnum, participantRoleEnum, quoteStatusEnum, quoteVersionStatusEnum, } from "./schema-shared.js";
5
5
  export const pipelines = pgTable("pipelines", {
6
6
  id: typeId("pipelines"),
7
- entityType: entityTypeEnum("entity_type").notNull().default("opportunity"),
7
+ entityType: entityTypeEnum("entity_type").notNull().default("quote"),
8
8
  name: text("name").notNull(),
9
9
  isDefault: boolean("is_default").notNull().default(false),
10
10
  sortOrder: integer("sort_order").notNull().default(0),
@@ -35,8 +35,8 @@ export const stages = pgTable("stages", {
35
35
  index("idx_stages_pipeline_sort").on(table.pipelineId, table.sortOrder, table.createdAt),
36
36
  uniqueIndex("uidx_stages_pipeline_name").on(table.pipelineId, table.name),
37
37
  ]);
38
- export const opportunities = pgTable("opportunities", {
39
- id: typeId("opportunities"),
38
+ export const quotes = pgTable("quotes", {
39
+ id: typeId("quotes"),
40
40
  title: text("title").notNull(),
41
41
  personId: typeIdRef("person_id").references(() => people.id, { onDelete: "set null" }),
42
42
  organizationId: typeIdRef("organization_id").references(() => organizations.id, {
@@ -49,7 +49,8 @@ export const opportunities = pgTable("opportunities", {
49
49
  .notNull()
50
50
  .references(() => stages.id, { onDelete: "restrict" }),
51
51
  ownerId: text("owner_id"),
52
- status: opportunityStatusEnum("status").notNull().default("open"),
52
+ status: quoteStatusEnum("status").notNull().default("open"),
53
+ acceptedVersionId: typeIdRef("accepted_version_id"),
53
54
  valueAmountCents: integer("value_amount_cents"),
54
55
  valueCurrency: text("value_currency"),
55
56
  expectedCloseDate: date("expected_close_date"),
@@ -62,24 +63,25 @@ export const opportunities = pgTable("opportunities", {
62
63
  stageChangedAt: timestamp("stage_changed_at", { withTimezone: true }).notNull().defaultNow(),
63
64
  closedAt: timestamp("closed_at", { withTimezone: true }),
64
65
  }, (table) => [
65
- index("idx_opportunities_person").on(table.personId),
66
- index("idx_opportunities_org").on(table.organizationId),
67
- index("idx_opportunities_pipeline").on(table.pipelineId),
68
- index("idx_opportunities_stage").on(table.stageId),
69
- index("idx_opportunities_owner").on(table.ownerId),
70
- index("idx_opportunities_status").on(table.status),
71
- index("idx_opportunities_person_updated").on(table.personId, table.updatedAt),
72
- index("idx_opportunities_org_updated").on(table.organizationId, table.updatedAt),
73
- index("idx_opportunities_pipeline_updated").on(table.pipelineId, table.updatedAt),
74
- index("idx_opportunities_stage_updated").on(table.stageId, table.updatedAt),
75
- index("idx_opportunities_owner_updated").on(table.ownerId, table.updatedAt),
76
- index("idx_opportunities_status_updated").on(table.status, table.updatedAt),
66
+ index("idx_quotes_person").on(table.personId),
67
+ index("idx_quotes_org").on(table.organizationId),
68
+ index("idx_quotes_pipeline").on(table.pipelineId),
69
+ index("idx_quotes_stage").on(table.stageId),
70
+ index("idx_quotes_owner").on(table.ownerId),
71
+ index("idx_quotes_status").on(table.status),
72
+ index("idx_quotes_accepted_version").on(table.acceptedVersionId),
73
+ index("idx_quotes_person_updated").on(table.personId, table.updatedAt),
74
+ index("idx_quotes_org_updated").on(table.organizationId, table.updatedAt),
75
+ index("idx_quotes_pipeline_updated").on(table.pipelineId, table.updatedAt),
76
+ index("idx_quotes_stage_updated").on(table.stageId, table.updatedAt),
77
+ index("idx_quotes_owner_updated").on(table.ownerId, table.updatedAt),
78
+ index("idx_quotes_status_updated").on(table.status, table.updatedAt),
77
79
  ]);
78
- export const opportunityParticipants = pgTable("opportunity_participants", {
79
- id: typeId("opportunity_participants"),
80
- opportunityId: typeIdRef("opportunity_id")
80
+ export const quoteParticipants = pgTable("quote_participants", {
81
+ id: typeId("quote_participants"),
82
+ quoteId: typeIdRef("quote_id")
81
83
  .notNull()
82
- .references(() => opportunities.id, { onDelete: "cascade" }),
84
+ .references(() => quotes.id, { onDelete: "cascade" }),
83
85
  personId: typeIdRef("person_id")
84
86
  .notNull()
85
87
  .references(() => people.id, { onDelete: "cascade" }),
@@ -87,16 +89,16 @@ export const opportunityParticipants = pgTable("opportunity_participants", {
87
89
  isPrimary: boolean("is_primary").notNull().default(false),
88
90
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
89
91
  }, (table) => [
90
- index("idx_opportunity_participants_opportunity").on(table.opportunityId),
91
- index("idx_opportunity_participants_opportunity_primary").on(table.opportunityId, table.isPrimary, table.createdAt),
92
- index("idx_opportunity_participants_person").on(table.personId),
93
- uniqueIndex("uidx_opportunity_participants_unique").on(table.opportunityId, table.personId),
92
+ index("idx_quote_participants_quote").on(table.quoteId),
93
+ index("idx_quote_participants_quote_primary").on(table.quoteId, table.isPrimary, table.createdAt),
94
+ index("idx_quote_participants_person").on(table.personId),
95
+ uniqueIndex("uidx_quote_participants_unique").on(table.quoteId, table.personId),
94
96
  ]);
95
- export const opportunityProducts = pgTable("opportunity_products", {
96
- id: typeId("opportunity_products"),
97
- opportunityId: typeIdRef("opportunity_id")
97
+ export const quoteProducts = pgTable("quote_products", {
98
+ id: typeId("quote_products"),
99
+ quoteId: typeIdRef("quote_id")
98
100
  .notNull()
99
- .references(() => opportunities.id, { onDelete: "cascade" }),
101
+ .references(() => quotes.id, { onDelete: "cascade" }),
100
102
  productId: text("product_id"),
101
103
  supplierServiceId: text("supplier_service_id"),
102
104
  nameSnapshot: text("name_snapshot").notNull(),
@@ -109,37 +111,47 @@ export const opportunityProducts = pgTable("opportunity_products", {
109
111
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
110
112
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
111
113
  }, (table) => [
112
- index("idx_opportunity_products_opportunity").on(table.opportunityId),
113
- index("idx_opportunity_products_opportunity_created").on(table.opportunityId, table.createdAt),
114
- index("idx_opportunity_products_product").on(table.productId),
115
- index("idx_opportunity_products_supplier_service").on(table.supplierServiceId),
114
+ index("idx_quote_products_quote").on(table.quoteId),
115
+ index("idx_quote_products_quote_created").on(table.quoteId, table.createdAt),
116
+ index("idx_quote_products_product").on(table.productId),
117
+ index("idx_quote_products_supplier_service").on(table.supplierServiceId),
116
118
  ]);
117
- export const quotes = pgTable("quotes", {
118
- id: typeId("quotes"),
119
- opportunityId: typeIdRef("opportunity_id")
119
+ export const quoteVersions = pgTable("quote_versions", {
120
+ id: typeId("quote_versions"),
121
+ quoteId: typeIdRef("quote_id")
120
122
  .notNull()
121
- .references(() => opportunities.id, { onDelete: "cascade" }),
122
- status: quoteStatusEnum("status").notNull().default("draft"),
123
+ .references(() => quotes.id, { onDelete: "cascade" }),
124
+ label: text("label"),
125
+ status: quoteVersionStatusEnum("status").notNull().default("draft"),
126
+ supersedesId: typeIdRef("supersedes_id").references(() => quoteVersions.id, {
127
+ onDelete: "set null",
128
+ }),
129
+ tripSnapshotId: text("trip_snapshot_id"),
123
130
  validUntil: date("valid_until"),
124
131
  currency: text("currency").notNull(),
125
132
  subtotalAmountCents: integer("subtotal_amount_cents").notNull().default(0),
126
133
  taxAmountCents: integer("tax_amount_cents").notNull().default(0),
127
134
  totalAmountCents: integer("total_amount_cents").notNull().default(0),
128
135
  notes: text("notes"),
136
+ sentAt: timestamp("sent_at", { withTimezone: true }),
137
+ viewedAt: timestamp("viewed_at", { withTimezone: true }),
138
+ decidedAt: timestamp("decided_at", { withTimezone: true }),
129
139
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
130
140
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
131
141
  archivedAt: timestamp("archived_at", { withTimezone: true }),
132
142
  }, (table) => [
133
- index("idx_quotes_opportunity").on(table.opportunityId),
134
- index("idx_quotes_status").on(table.status),
135
- index("idx_quotes_opportunity_updated").on(table.opportunityId, table.updatedAt),
136
- index("idx_quotes_status_updated").on(table.status, table.updatedAt),
143
+ index("idx_quote_versions_quote").on(table.quoteId),
144
+ index("idx_quote_versions_status").on(table.status),
145
+ index("idx_quote_versions_supersedes").on(table.supersedesId),
146
+ index("idx_quote_versions_trip_snapshot").on(table.tripSnapshotId),
147
+ index("idx_quote_versions_quote_updated").on(table.quoteId, table.updatedAt),
148
+ index("idx_quote_versions_status_updated").on(table.status, table.updatedAt),
137
149
  ]);
138
- export const quoteLines = pgTable("quote_lines", {
139
- id: typeId("quote_lines"),
140
- quoteId: typeIdRef("quote_id")
150
+ export const quoteVersionLines = pgTable("quote_version_lines", {
151
+ id: typeId("quote_version_lines"),
152
+ quoteVersionId: typeIdRef("quote_version_id")
141
153
  .notNull()
142
- .references(() => quotes.id, { onDelete: "cascade" }),
154
+ .references(() => quoteVersions.id, { onDelete: "cascade" }),
143
155
  productId: text("product_id"),
144
156
  supplierServiceId: text("supplier_service_id"),
145
157
  description: text("description").notNull(),
@@ -150,8 +162,8 @@ export const quoteLines = pgTable("quote_lines", {
150
162
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
151
163
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
152
164
  }, (table) => [
153
- index("idx_quote_lines_quote").on(table.quoteId),
154
- index("idx_quote_lines_quote_created").on(table.quoteId, table.createdAt),
155
- index("idx_quote_lines_product").on(table.productId),
156
- index("idx_quote_lines_supplier_service").on(table.supplierServiceId),
165
+ index("idx_quote_version_lines_version").on(table.quoteVersionId),
166
+ index("idx_quote_version_lines_version_created").on(table.quoteVersionId, table.createdAt),
167
+ index("idx_quote_version_lines_product").on(table.productId),
168
+ index("idx_quote_version_lines_supplier_service").on(table.supplierServiceId),
157
169
  ]);
@@ -1,10 +1,10 @@
1
- export declare const entityTypeEnum: import("drizzle-orm/pg-core").PgEnum<["organization", "person", "opportunity", "quote", "activity"]>;
1
+ export declare const entityTypeEnum: import("drizzle-orm/pg-core").PgEnum<["organization", "person", "quote", "activity"]>;
2
2
  export declare const relationTypeEnum: import("drizzle-orm/pg-core").PgEnum<["client", "partner", "supplier", "other"]>;
3
3
  export declare const communicationChannelEnum: import("drizzle-orm/pg-core").PgEnum<["email", "phone", "whatsapp", "sms", "meeting", "other"]>;
4
4
  export declare const communicationDirectionEnum: import("drizzle-orm/pg-core").PgEnum<["inbound", "outbound"]>;
5
5
  export declare const recordStatusEnum: import("drizzle-orm/pg-core").PgEnum<["active", "inactive", "archived"]>;
6
- export declare const opportunityStatusEnum: import("drizzle-orm/pg-core").PgEnum<["open", "won", "lost", "archived"]>;
7
- export declare const quoteStatusEnum: import("drizzle-orm/pg-core").PgEnum<["draft", "sent", "accepted", "expired", "rejected", "archived"]>;
6
+ export declare const quoteStatusEnum: import("drizzle-orm/pg-core").PgEnum<["open", "won", "lost", "archived"]>;
7
+ export declare const quoteVersionStatusEnum: import("drizzle-orm/pg-core").PgEnum<["draft", "sent", "accepted", "declined", "superseded", "expired"]>;
8
8
  export declare const activityTypeEnum: import("drizzle-orm/pg-core").PgEnum<["call", "email", "meeting", "task", "follow_up", "note"]>;
9
9
  export declare const activityStatusEnum: import("drizzle-orm/pg-core").PgEnum<["planned", "done", "cancelled"]>;
10
10
  export declare const activityLinkRoleEnum: import("drizzle-orm/pg-core").PgEnum<["primary", "related"]>;
@@ -1 +1 @@
1
- {"version":3,"file":"schema-shared.d.ts","sourceRoot":"","sources":["../src/schema-shared.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,sGAMzB,CAAA;AAEF,eAAO,MAAM,gBAAgB,kFAAsE,CAAA;AAEnG,eAAO,MAAM,wBAAwB,iGAOnC,CAAA;AAEF,eAAO,MAAM,0BAA0B,+DAA6D,CAAA;AAEpG,eAAO,MAAM,gBAAgB,0EAA8D,CAAA;AAE3F,eAAO,MAAM,qBAAqB,2EAKhC,CAAA;AAEF,eAAO,MAAM,eAAe,wGAO1B,CAAA;AAEF,eAAO,MAAM,gBAAgB,iGAO3B,CAAA;AAEF,eAAO,MAAM,kBAAkB,wEAA8D,CAAA;AAE7F,eAAO,MAAM,oBAAoB,8DAAuD,CAAA;AAExF,eAAO,MAAM,mBAAmB,oGAM9B,CAAA;AAEF,eAAO,MAAM,mBAAmB,+IAY9B,CAAA"}
1
+ {"version":3,"file":"schema-shared.d.ts","sourceRoot":"","sources":["../src/schema-shared.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,uFAAyE,CAAA;AAEpG,eAAO,MAAM,gBAAgB,kFAAsE,CAAA;AAEnG,eAAO,MAAM,wBAAwB,iGAOnC,CAAA;AAEF,eAAO,MAAM,0BAA0B,+DAA6D,CAAA;AAEpG,eAAO,MAAM,gBAAgB,0EAA8D,CAAA;AAE3F,eAAO,MAAM,eAAe,2EAA8D,CAAA;AAE1F,eAAO,MAAM,sBAAsB,0GAOjC,CAAA;AAEF,eAAO,MAAM,gBAAgB,iGAO3B,CAAA;AAEF,eAAO,MAAM,kBAAkB,wEAA8D,CAAA;AAE7F,eAAO,MAAM,oBAAoB,8DAAuD,CAAA;AAExF,eAAO,MAAM,mBAAmB,oGAM9B,CAAA;AAEF,eAAO,MAAM,mBAAmB,+IAY9B,CAAA"}
@@ -1,11 +1,5 @@
1
1
  import { pgEnum } from "drizzle-orm/pg-core";
2
- export const entityTypeEnum = pgEnum("entity_type", [
3
- "organization",
4
- "person",
5
- "opportunity",
6
- "quote",
7
- "activity",
8
- ]);
2
+ export const entityTypeEnum = pgEnum("entity_type", ["organization", "person", "quote", "activity"]);
9
3
  export const relationTypeEnum = pgEnum("relation_type", ["client", "partner", "supplier", "other"]);
10
4
  export const communicationChannelEnum = pgEnum("communication_channel", [
11
5
  "email",
@@ -17,19 +11,14 @@ export const communicationChannelEnum = pgEnum("communication_channel", [
17
11
  ]);
18
12
  export const communicationDirectionEnum = pgEnum("communication_direction", ["inbound", "outbound"]);
19
13
  export const recordStatusEnum = pgEnum("record_status", ["active", "inactive", "archived"]);
20
- export const opportunityStatusEnum = pgEnum("opportunity_status", [
21
- "open",
22
- "won",
23
- "lost",
24
- "archived",
25
- ]);
26
- export const quoteStatusEnum = pgEnum("quote_status", [
14
+ export const quoteStatusEnum = pgEnum("quote_status", ["open", "won", "lost", "archived"]);
15
+ export const quoteVersionStatusEnum = pgEnum("quote_version_status", [
27
16
  "draft",
28
17
  "sent",
29
18
  "accepted",
19
+ "declined",
20
+ "superseded",
30
21
  "expired",
31
- "rejected",
32
- "archived",
33
22
  ]);
34
23
  export const activityTypeEnum = pgEnum("activity_type", [
35
24
  "call",
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Customer signals — lighter than `opportunities` (no deal value or
2
+ * Customer signals — lighter than `quotes` (no deal value or
3
3
  * stages), heavier than `segments` (lifecycle + assignment). Records
4
4
  * "person X expressed interest in product/departure Y from source Z,
5
5
  * status pending". The most common use cases:
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Customer signals — lighter than `opportunities` (no deal value or
2
+ * Customer signals — lighter than `quotes` (no deal value or
3
3
  * stages), heavier than `segments` (lifecycle + assignment). Records
4
4
  * "person X expressed interest in product/departure Y from source Z,
5
5
  * status pending". The most common use cases:
@@ -1,6 +1,6 @@
1
1
  import { identityAddresses, identityContactPoints, identityNamedContacts, } from "@voyantjs/identity/schema";
2
2
  import { and, eq, inArray, ne, or, sql } from "drizzle-orm";
3
- import { activityLinks, activityParticipants, communicationLog, customerSignals, customFieldValues, opportunities, opportunityParticipants, organizationNotes, organizations, people, personDocuments, personNotes, personPaymentMethods, personRelationships, segmentMembers, } from "../schema.js";
3
+ import { activityLinks, activityParticipants, communicationLog, customerSignals, customFieldValues, organizationNotes, organizations, people, personDocuments, personNotes, personPaymentMethods, personRelationships, quoteParticipants, quotes, segmentMembers, } from "../schema.js";
4
4
  import { hydratePeople, organizationEntityType, personEntityType } from "./accounts-shared.js";
5
5
  export class CrmMergeError extends Error {
6
6
  status;
@@ -156,10 +156,10 @@ async function mergeEntityLinks(db, entityType, keepId, mergeId) {
156
156
  .where(and(eq(customFieldValues.entityType, entityType), eq(customFieldValues.entityId, mergeId)));
157
157
  }
158
158
  async function dedupePersonJoinTables(db, keepId, mergeId) {
159
- await db.delete(opportunityParticipants).where(and(eq(opportunityParticipants.personId, mergeId), sql `EXISTS (
159
+ await db.delete(quoteParticipants).where(and(eq(quoteParticipants.personId, mergeId), sql `EXISTS (
160
160
  SELECT 1
161
- FROM opportunity_participants keep_participant
162
- WHERE keep_participant.opportunity_id = ${opportunityParticipants.opportunityId}
161
+ FROM quote_participants keep_participant
162
+ WHERE keep_participant.quote_id = ${quoteParticipants.quoteId}
163
163
  AND keep_participant.person_id = ${keepId}
164
164
  )`));
165
165
  await db.delete(activityParticipants).where(and(eq(activityParticipants.personId, mergeId), sql `EXISTS (
@@ -258,13 +258,13 @@ export const accountMergeService = {
258
258
  .set({ personId: keepId })
259
259
  .where(eq(communicationLog.personId, mergeId));
260
260
  await tx
261
- .update(opportunities)
261
+ .update(quotes)
262
262
  .set({ personId: keepId, updatedAt: new Date() })
263
- .where(eq(opportunities.personId, mergeId));
263
+ .where(eq(quotes.personId, mergeId));
264
264
  await tx
265
- .update(opportunityParticipants)
265
+ .update(quoteParticipants)
266
266
  .set({ personId: keepId })
267
- .where(eq(opportunityParticipants.personId, mergeId));
267
+ .where(eq(quoteParticipants.personId, mergeId));
268
268
  await tx
269
269
  .update(activityParticipants)
270
270
  .set({ personId: keepId })
@@ -347,9 +347,9 @@ export const accountMergeService = {
347
347
  .set({ organizationId: keepId })
348
348
  .where(eq(communicationLog.organizationId, mergeId));
349
349
  await tx
350
- .update(opportunities)
350
+ .update(quotes)
351
351
  .set({ organizationId: keepId, updatedAt: new Date() })
352
- .where(eq(opportunities.organizationId, mergeId));
352
+ .where(eq(quotes.organizationId, mergeId));
353
353
  await updateOptionalReferences(tx, OPTIONAL_ORGANIZATION_REFERENCES, keepId, mergeId);
354
354
  await updateOptionalEntityTargetReferences(tx, OPTIONAL_ORGANIZATION_ENTITY_TARGET_REFERENCES, keepId, mergeId);
355
355
  await tx.delete(organizations).where(eq(organizations.id, mergeId));
@@ -107,14 +107,14 @@ export declare const activitiesService: {
107
107
  tableName: "activity_links";
108
108
  dataType: "string";
109
109
  columnType: "PgEnumColumn";
110
- data: "organization" | "person" | "opportunity" | "quote" | "activity";
110
+ data: "organization" | "person" | "quote" | "activity";
111
111
  driverParam: string;
112
112
  notNull: true;
113
113
  hasDefault: false;
114
114
  isPrimaryKey: false;
115
115
  isAutoincrement: false;
116
116
  hasRuntimeDefault: false;
117
- enumValues: ["organization", "person", "opportunity", "quote", "activity"];
117
+ enumValues: ["organization", "person", "quote", "activity"];
118
118
  baseColumn: never;
119
119
  identity: undefined;
120
120
  generated: undefined;
@@ -173,7 +173,7 @@ export declare const activitiesService: {
173
173
  }, "single", Record<"activity_links", "not-null">, false, "where" | "orderBy", {
174
174
  id: string;
175
175
  activityId: string;
176
- entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
176
+ entityType: "organization" | "person" | "quote" | "activity";
177
177
  entityId: string;
178
178
  role: "primary" | "related";
179
179
  createdAt: Date;
@@ -217,14 +217,14 @@ export declare const activitiesService: {
217
217
  tableName: "activity_links";
218
218
  dataType: "string";
219
219
  columnType: "PgEnumColumn";
220
- data: "organization" | "person" | "opportunity" | "quote" | "activity";
220
+ data: "organization" | "person" | "quote" | "activity";
221
221
  driverParam: string;
222
222
  notNull: true;
223
223
  hasDefault: false;
224
224
  isPrimaryKey: false;
225
225
  isAutoincrement: false;
226
226
  hasRuntimeDefault: false;
227
- enumValues: ["organization", "person", "opportunity", "quote", "activity"];
227
+ enumValues: ["organization", "person", "quote", "activity"];
228
228
  baseColumn: never;
229
229
  identity: undefined;
230
230
  generated: undefined;
@@ -285,7 +285,7 @@ export declare const activitiesService: {
285
285
  id: string;
286
286
  createdAt: Date;
287
287
  role: "primary" | "related";
288
- entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
288
+ entityType: "organization" | "person" | "quote" | "activity";
289
289
  entityId: string;
290
290
  activityId: string;
291
291
  } | undefined>;
@@ -10,7 +10,7 @@ export declare const customFieldsService: {
10
10
  listCustomFieldDefinitions(db: PostgresJsDatabase, query: CustomFieldDefinitionListQuery): Promise<{
11
11
  data: {
12
12
  id: string;
13
- entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
13
+ entityType: "organization" | "person" | "quote" | "activity";
14
14
  key: string;
15
15
  label: string;
16
16
  fieldType: "boolean" | "json" | "date" | "text" | "set" | "enum" | "phone" | "varchar" | "double" | "monetary" | "address";
@@ -29,7 +29,7 @@ export declare const customFieldsService: {
29
29
  }>;
30
30
  getCustomFieldDefinitionById(db: PostgresJsDatabase, id: string): Promise<{
31
31
  id: string;
32
- entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
32
+ entityType: "organization" | "person" | "quote" | "activity";
33
33
  key: string;
34
34
  label: string;
35
35
  fieldType: "boolean" | "json" | "date" | "text" | "set" | "enum" | "phone" | "varchar" | "double" | "monetary" | "address";
@@ -51,7 +51,7 @@ export declare const customFieldsService: {
51
51
  createdAt: Date;
52
52
  key: string;
53
53
  updatedAt: Date;
54
- entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
54
+ entityType: "organization" | "person" | "quote" | "activity";
55
55
  label: string;
56
56
  fieldType: "boolean" | "json" | "date" | "text" | "set" | "enum" | "phone" | "varchar" | "double" | "monetary" | "address";
57
57
  isRequired: boolean;
@@ -59,7 +59,7 @@ export declare const customFieldsService: {
59
59
  } | undefined>;
60
60
  updateCustomFieldDefinition(db: PostgresJsDatabase, id: string, data: UpdateCustomFieldDefinitionInput): Promise<{
61
61
  id: string;
62
- entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
62
+ entityType: "organization" | "person" | "quote" | "activity";
63
63
  key: string;
64
64
  label: string;
65
65
  fieldType: "boolean" | "json" | "date" | "text" | "set" | "enum" | "phone" | "varchar" | "double" | "monetary" | "address";
@@ -79,7 +79,7 @@ export declare const customFieldsService: {
79
79
  data: {
80
80
  id: string;
81
81
  definitionId: string;
82
- entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
82
+ entityType: "organization" | "person" | "quote" | "activity";
83
83
  entityId: string;
84
84
  textValue: string | null;
85
85
  numberValue: number | null;
@@ -99,7 +99,7 @@ export declare const customFieldsService: {
99
99
  id: string;
100
100
  createdAt: Date;
101
101
  updatedAt: Date;
102
- entityType: "organization" | "person" | "opportunity" | "quote" | "activity";
102
+ entityType: "organization" | "person" | "quote" | "activity";
103
103
  entityId: string;
104
104
  definitionId: string;
105
105
  textValue: string | null;