@aglyn/plugins-crm 1.0.0 → 1.2.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 (166) hide show
  1. package/package.json +14 -14
  2. package/src/lib/components/activity-link-fields.d.ts +34 -0
  3. package/src/lib/components/activity-link-fields.js +141 -0
  4. package/src/lib/components/activity-link-fields.js.map +1 -0
  5. package/src/lib/components/activity-list.d.ts +8 -0
  6. package/src/lib/components/activity-list.js +4 -2
  7. package/src/lib/components/activity-list.js.map +1 -1
  8. package/src/lib/components/activity-queries.d.ts +7 -2
  9. package/src/lib/components/activity-queries.js +7 -3
  10. package/src/lib/components/activity-queries.js.map +1 -1
  11. package/src/lib/components/company-contact-roles-card.d.ts +42 -0
  12. package/src/lib/components/company-contact-roles-card.js +137 -0
  13. package/src/lib/components/company-contact-roles-card.js.map +1 -0
  14. package/src/lib/components/company-detail-page.js +12 -1
  15. package/src/lib/components/company-detail-page.js.map +1 -1
  16. package/src/lib/components/company-edit-drawer.js +9 -6
  17. package/src/lib/components/company-edit-drawer.js.map +1 -1
  18. package/src/lib/components/company-picker.js +4 -2
  19. package/src/lib/components/company-picker.js.map +1 -1
  20. package/src/lib/components/contact-associations-card.js +15 -1
  21. package/src/lib/components/contact-associations-card.js.map +1 -1
  22. package/src/lib/components/contact-detail-page.js +13 -14
  23. package/src/lib/components/contact-detail-page.js.map +1 -1
  24. package/src/lib/components/contact-known-by-card.d.ts +2 -1
  25. package/src/lib/components/contact-known-by-card.js +16 -3
  26. package/src/lib/components/contact-known-by-card.js.map +1 -1
  27. package/src/lib/components/contact-list-columns.js +5 -4
  28. package/src/lib/components/contact-list-columns.js.map +1 -1
  29. package/src/lib/components/contact-properties-card.js +41 -20
  30. package/src/lib/components/contact-properties-card.js.map +1 -1
  31. package/src/lib/components/contact-roles-editor.d.ts +54 -0
  32. package/src/lib/components/contact-roles-editor.js +270 -0
  33. package/src/lib/components/contact-roles-editor.js.map +1 -0
  34. package/src/lib/components/contacts-section.js +6 -4
  35. package/src/lib/components/contacts-section.js.map +1 -1
  36. package/src/lib/components/crm-console-sections.js +1 -1
  37. package/src/lib/components/crm-console-sections.js.map +1 -1
  38. package/src/lib/components/crm-record-picker.d.ts +19 -0
  39. package/src/lib/components/crm-record-picker.js +40 -11
  40. package/src/lib/components/crm-record-picker.js.map +1 -1
  41. package/src/lib/components/crm-related-to-picker.d.ts +33 -0
  42. package/src/lib/components/crm-related-to-picker.js +135 -0
  43. package/src/lib/components/crm-related-to-picker.js.map +1 -0
  44. package/src/lib/components/crm-site-picker.d.ts +13 -1
  45. package/src/lib/components/crm-site-picker.js +15 -6
  46. package/src/lib/components/crm-site-picker.js.map +1 -1
  47. package/src/lib/components/crm-transfer-buttons.d.ts +5 -0
  48. package/src/lib/components/crm-transfer-buttons.js +9 -6
  49. package/src/lib/components/crm-transfer-buttons.js.map +1 -1
  50. package/src/lib/components/deal-contact-roles-card.js +21 -239
  51. package/src/lib/components/deal-contact-roles-card.js.map +1 -1
  52. package/src/lib/components/deal-detail-page.js +2 -1
  53. package/src/lib/components/deal-detail-page.js.map +1 -1
  54. package/src/lib/components/deal-edit-drawer.js +11 -7
  55. package/src/lib/components/deal-edit-drawer.js.map +1 -1
  56. package/src/lib/components/deals-section.js +5 -4
  57. package/src/lib/components/deals-section.js.map +1 -1
  58. package/src/lib/components/log-activity-dialog.d.ts +27 -9
  59. package/src/lib/components/log-activity-dialog.js +96 -32
  60. package/src/lib/components/log-activity-dialog.js.map +1 -1
  61. package/src/lib/components/new-contact-drawer.d.ts +7 -3
  62. package/src/lib/components/new-contact-drawer.js +27 -15
  63. package/src/lib/components/new-contact-drawer.js.map +1 -1
  64. package/src/lib/components/pipeline-stages-dialog.js +5 -1
  65. package/src/lib/components/pipeline-stages-dialog.js.map +1 -1
  66. package/src/lib/components/record-activity-card.d.ts +11 -2
  67. package/src/lib/components/record-activity-card.js +90 -5
  68. package/src/lib/components/record-activity-card.js.map +1 -1
  69. package/src/lib/components/settings-section.d.ts +4 -2
  70. package/src/lib/components/settings-section.js +7 -5
  71. package/src/lib/components/settings-section.js.map +1 -1
  72. package/src/lib/hooks/crm-activity-client-reads.d.ts +8 -0
  73. package/src/lib/hooks/crm-activity-client-reads.js +50 -0
  74. package/src/lib/hooks/crm-activity-client-reads.js.map +1 -0
  75. package/src/lib/hooks/use-campaign-filing-log.d.ts +2 -1
  76. package/src/lib/hooks/use-campaign-filing-log.js +10 -3
  77. package/src/lib/hooks/use-campaign-filing-log.js.map +1 -1
  78. package/src/lib/hooks/use-crm-org-mount.d.ts +8 -6
  79. package/src/lib/hooks/use-crm-org-mount.js +2 -1
  80. package/src/lib/hooks/use-crm-org-mount.js.map +1 -1
  81. package/src/lib/hooks/use-crm-record-names.d.ts +3 -2
  82. package/src/lib/hooks/use-crm-record-names.js +4 -4
  83. package/src/lib/hooks/use-crm-record-names.js.map +1 -1
  84. package/src/lib/hooks/use-crm-scope.d.ts +17 -5
  85. package/src/lib/hooks/use-crm-scope.js +12 -5
  86. package/src/lib/hooks/use-crm-scope.js.map +1 -1
  87. package/src/lib/model/contact-holder.d.ts +12 -0
  88. package/src/lib/model/contact-holder.js +20 -1
  89. package/src/lib/model/contact-holder.js.map +1 -1
  90. package/src/lib/model/contact-record.d.ts +5 -0
  91. package/src/lib/model/contact-record.js +7 -1
  92. package/src/lib/model/contact-record.js.map +1 -1
  93. package/src/lib/model/contact-update.d.ts +6 -0
  94. package/src/lib/model/contact-update.js +1 -0
  95. package/src/lib/model/contact-update.js.map +1 -1
  96. package/src/lib/model/crm-activity-link.d.ts +117 -0
  97. package/src/lib/model/crm-activity-link.js +113 -0
  98. package/src/lib/model/crm-activity-link.js.map +1 -0
  99. package/src/lib/model/crm-api.d.ts +4 -1
  100. package/src/lib/model/crm-api.js +9 -5
  101. package/src/lib/model/crm-api.js.map +1 -1
  102. package/src/lib/model/deal-board-model.js +5 -3
  103. package/src/lib/model/deal-board-model.js.map +1 -1
  104. package/src/lib/model/deal-contact-roles.d.ts +25 -1
  105. package/src/lib/model/deal-contact-roles.js +30 -4
  106. package/src/lib/model/deal-contact-roles.js.map +1 -1
  107. package/src/lib/model/native-vocabulary.d.ts +9 -0
  108. package/src/lib/model/native-vocabulary.js +13 -0
  109. package/src/lib/model/native-vocabulary.js.map +1 -1
  110. package/src/lib/model/settle-stage-names.d.ts +25 -0
  111. package/src/lib/model/settle-stage-names.js +29 -0
  112. package/src/lib/model/settle-stage-names.js.map +1 -0
  113. package/src/lib/native-nav.js +1 -1
  114. package/src/lib/native-nav.js.map +1 -1
  115. package/src/lib/server/add-contact-by-hand.d.ts +84 -0
  116. package/src/lib/server/add-contact-by-hand.js +212 -0
  117. package/src/lib/server/add-contact-by-hand.js.map +1 -0
  118. package/src/lib/server/api-v1/contacts.js +61 -23
  119. package/src/lib/server/api-v1/contacts.js.map +1 -1
  120. package/src/lib/server/api-v1/crm-activities.js +13 -3
  121. package/src/lib/server/api-v1/crm-activities.js.map +1 -1
  122. package/src/lib/server/api-v1/crm-pipelines.d.ts +1 -1
  123. package/src/lib/server/api-v1/crm-pipelines.js +8 -2
  124. package/src/lib/server/api-v1/crm-pipelines.js.map +1 -1
  125. package/src/lib/server/api-v1/crm-shared.d.ts +16 -9
  126. package/src/lib/server/api-v1/crm-shared.js +23 -11
  127. package/src/lib/server/api-v1/crm-shared.js.map +1 -1
  128. package/src/lib/server/api-v1/openapi.js +3 -3
  129. package/src/lib/server/api-v1/openapi.js.map +1 -1
  130. package/src/lib/server/automation-steps.js +11 -9
  131. package/src/lib/server/automation-steps.js.map +1 -1
  132. package/src/lib/server/campaign-filing-activity.js +7 -2
  133. package/src/lib/server/campaign-filing-activity.js.map +1 -1
  134. package/src/lib/server/contact-update.d.ts +4 -0
  135. package/src/lib/server/contact-update.js +71 -10
  136. package/src/lib/server/contact-update.js.map +1 -1
  137. package/src/lib/server/convert-host-lead.js +13 -2
  138. package/src/lib/server/convert-host-lead.js.map +1 -1
  139. package/src/lib/server/convert-open-lead.js +8 -1
  140. package/src/lib/server/convert-open-lead.js.map +1 -1
  141. package/src/lib/server/crm-activity-company.d.ts +25 -0
  142. package/src/lib/server/crm-activity-company.js +34 -0
  143. package/src/lib/server/crm-activity-company.js.map +1 -0
  144. package/src/lib/server/crm-inbound-email.js +21 -15
  145. package/src/lib/server/crm-inbound-email.js.map +1 -1
  146. package/src/lib/server/crm-sharing.js +9 -2
  147. package/src/lib/server/crm-sharing.js.map +1 -1
  148. package/src/lib/server/deal-contact-roles.d.ts +2 -0
  149. package/src/lib/server/deal-contact-roles.js +38 -1
  150. package/src/lib/server/deal-contact-roles.js.map +1 -1
  151. package/src/lib/server/email-send.js +10 -8
  152. package/src/lib/server/email-send.js.map +1 -1
  153. package/src/lib/server/merge-contacts.js +6 -2
  154. package/src/lib/server/merge-contacts.js.map +1 -1
  155. package/src/lib/server/org-caller.d.ts +8 -0
  156. package/src/lib/server/org-caller.js +10 -0
  157. package/src/lib/server/org-caller.js.map +1 -1
  158. package/src/lib/server/record-timeline.d.ts +3 -1
  159. package/src/lib/server/record-timeline.js +11 -3
  160. package/src/lib/server/record-timeline.js.map +1 -1
  161. package/src/lib/server.js +152 -43
  162. package/src/lib/server.js.map +1 -1
  163. package/src/lib/transfer/contacts.js +83 -48
  164. package/src/lib/transfer/contacts.js.map +1 -1
  165. package/src/lib/transfer/fields.js +1 -2
  166. package/src/lib/transfer/fields.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/transfer/contacts.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * CONTACTS ON THE TRANSFER FRAMEWORK (AGL-3527) — the server half of\n * `crm.contacts`.\n *\n * A contact is one person shared by every site of the workspace, and each\n * site's consent group keeps its own profile of them — its facet. So a\n * transfer reads and writes the facet of the site it was opened under: an\n * export at the organization level reads each person's primary holder, as\n * the org-level list does; an import always names a site, because a\n * contact is a person some site met.\n *\n * ## The writes are the CRM's own\n *\n * A new person goes through `captureHostContact`, the door every capture\n * goes through — the records band, the erasure check, the consent group's\n * facet, `contactCreated` for the automations, the company by the email's\n * domain and the owner by the assignment rules when the row names neither.\n * A matched person is changed through the contact profile route's own\n * patch (`contactPatch`): the composed name, the company link and its\n * contact counts, the list's filter keys. A stage that moves raises\n * `contactStageChanged`, as the stage route does.\n *\n * ## What a file may not do\n *\n * The locked rules: an existing contact's email is who they are; consent is\n * never taken from a file; a stage moves forward only; Do not call is\n * turned on by a file and never off; the full name follows the first and\n * last names once either is set. The plan holds each one back by row and\n * names it, so the person acknowledges it before anything is written.\n *=========================================*/\n\nimport {\n composeContactName,\n type ConsentGroup,\n contactDisplayName,\n contactFacetPath,\n type ContactFieldDefinition,\n CRM_COLLECTIONS,\n interactionsForGroup,\n isContactLifecycleStage,\n normalizeContactBirthdate,\n normalizePhone,\n planContactDetach,\n readContactFacet,\n readMarketingBasis,\n} from '@aglyn/aglyn/server'\nimport { CONTACT_LIFECYCLE_STAGE_LABELS } from '@aglyn/aglyn/app-utils/crm'\nimport { CONTACT_EXTRA_PHONE_FIELDS as PHONE_FIELDS } from '@aglyn/aglyn/app-utils/contacts'\nimport {\n buildTransferPlan,\n planTransferUndo,\n rankTransferLookupSuggestions,\n TRANSFER_ID_FIELD,\n transferLookupNewName,\n type PlannedTransferRow,\n type TransferRowResult,\n type TransferUndoEntry,\n type TransferUndoStep,\n} from '@aglyn/aglyn/data-transfer'\nimport type { TransferRecordsHooks } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\nimport {\n prepareContactCaptureBatch,\n removeContactKeepingRefusals,\n restampCrmListFieldsOf,\n} from '@aglyn/tenant-data-admin'\nimport { emitHostEvent } from '@aglyn/tenant-runtime'\nimport { FieldValue } from 'firebase-admin/firestore'\nimport { contactPrimaryGroup } from '../model/contact-holder'\nimport type { ContactUpdateFields } from '../model/contact-update'\nimport { captureHostContact } from '../server/capture-host-contact'\nimport { CONTACT_NOTES_MAX } from '../server/contact-profile'\nimport {\n cachedContactReader,\n clearReportsToOf,\n CONTACT_REPORTS_TO_LOOP_REFUSAL,\n CONTACT_REPORTS_TO_SELF_REFUSAL,\n contactFacetHolders,\n contactReportsToLoops,\n} from '../server/contact-reports-to'\nimport { contactPatch, settleCompanyCounts } from '../server/contact-update'\nimport { sweepDealContactRoles } from '../server/deal-contact-roles'\nimport { CONTACT_ALIASES } from './aliases'\nimport {\n addCrmPicklistValues,\n addressFromValues,\n addressValues,\n countCrmExport,\n crmCustomDefinitions,\n crmMemberEmails,\n crmMembersTarget,\n crmPicklistLists,\n crmRecordsRoom,\n crmTransferEnv,\n type CrmTransferEnv,\n customTransferValues,\n customWriteValues,\n eachWithinBudget,\n failureMessage,\n holdBackChanges,\n IN_LIMIT,\n isoOf,\n lookupByField,\n lookupById,\n lookupResult,\n pickValues,\n plannedValues,\n readCrmExportPage,\n requireCrmSuite,\n requireSite,\n textOf,\n TransferEngineError,\n visibleIn,\n} from './common'\nimport { companyForName } from './companies'\nimport {\n CONTACT_TRANSFER_DERIVED,\n CONTACT_TRANSFER_FIELDS,\n CONTACT_TRANSFER_GROUPS,\n CRM_MEMBERS_TARGET,\n CRM_TIMESTAMP_FIELDS,\n crmCustomTransferFields,\n crmLifecycleStageOf,\n crmLifecycleStageRank,\n} from './fields'\n\n/** The sentence an imported person's timeline opens with. */\nexport const CONTACT_TRANSFER_INTERACTION_SUMMARY = 'Imported from a file'\n\nconst SUITE_ACT = 'Importing contacts'\n\nconst contactsOf = (env: CrmTransferEnv) => env.orgRef.collection('contacts')\n\n/** The holder a contact is read through: the site's group, else the person's primary holder. */\nfunction holderOf(env: CrmTransferEnv, contact: Record<string, unknown>): ConsentGroup {\n return env.group ?? contactPrimaryGroup(contact, env.org)\n}\n\n/** Why a capture refused a person, in the result's words. */\nconst CAPTURE_REFUSALS: Readonly<Record<string, string>> = {\n band: 'The contact limit is reached.',\n 'invalid-email': 'Not a valid email address.',\n erased: 'Erased from this workspace at their request.',\n error: 'The contact could not be saved.',\n}\n\n/**\n * One contact as values by field id, read through one holder's facet. A\n * lookup and an undo read links by id (`ids`), so the plan compares what is\n * stored; an export writes names a file can carry back (`names`).\n */\nexport function contactTransferValues(\n id: string,\n contact: Record<string, unknown>,\n group: ConsentGroup,\n definitions: readonly ContactFieldDefinition[],\n names?: { owner: (uid: string) => string | undefined; manager: (id: string) => string | undefined },\n): Record<string, unknown> {\n const facet = readContactFacet(contact, group.groupId)\n const text = (value: unknown) => textOf(value) || null\n const stage = isContactLifecycleStage(facet.lifecycleStage) ? CONTACT_LIFECYCLE_STAGE_LABELS[facet.lifecycleStage] : null\n const basis = group.groupId ? readMarketingBasis(contact, group).basis : 'unrecorded'\n const ownerUid = text(facet.ownerUid)\n const managerId = text(facet.reportsToContactId)\n return {\n // The name first: a record's label is the first text it holds.\n name: text(contactDisplayName(contact, group.groupId)),\n email: text(contact['email']),\n salutation: text(facet.salutation),\n firstName: text(facet.firstName),\n lastName: text(facet.lastName),\n birthdate: text(facet.birthdate),\n phone: text(facet.phone),\n mobilePhone: text(facet.mobilePhone),\n homePhone: text(facet.homePhone),\n otherPhone: text(facet.otherPhone),\n fax: text(facet.fax),\n doNotCall: facet.doNotCall === true,\n assistantName: text(facet.assistantName),\n assistantPhone: text(facet.assistantPhone),\n jobTitle: text(facet.jobTitle),\n department: text(facet.department),\n company: names ? text(facet.companyName) : text(facet.companyId),\n reportsTo: managerId ? (names ? (names.manager(managerId) ?? managerId) : managerId) : null,\n ...addressValues('mailing', facet.address),\n ...addressValues('other', facet.otherAddress),\n owner: ownerUid ? (names ? (names.owner(ownerUid) ?? ownerUid) : ownerUid) : null,\n lifecycleStage: stage,\n leadSource: text(facet.leadSource),\n tags: Array.isArray(facet.tags) ? facet.tags : [],\n notes: text(facet.notes),\n marketingConsent: basis === 'granted' ? true : basis === 'declined' ? false : null,\n sources: Object.keys(facet.sources ?? {}),\n lastInteractionAt: isoOf(interactionsForGroup(facet.interactions, group.hostIds)[0]?.atMs),\n lastEngagedAt: isoOf(facet.lastEmailEngagementAtMs),\n createdAt: isoOf(contact['createdAt']),\n updatedAt: isoOf(contact['updatedAt']),\n ...customTransferValues(definitions, facet.custom),\n [TRANSFER_ID_FIELD]: id,\n }\n}\n\n/** The contacts these ids name, as values through the site's facet. */\nasync function readContacts(\n env: CrmTransferEnv,\n ids: readonly string[],\n definitions: readonly ContactFieldDefinition[],\n): Promise<Map<string, Record<string, unknown>>> {\n const out = new Map<string, Record<string, unknown>>()\n for (let at = 0; at < ids.length; at += 500) {\n const page = ids.slice(at, at + 500).filter((id) => id && !id.includes('/'))\n if (!page.length) continue\n for (const snapshot of await env.firestore.getAll(...page.map((id) => contactsOf(env).doc(id)))) {\n const data = snapshot.data()\n if (snapshot.exists && data && visibleIn(env, data['visibleTo'])) {\n out.set(snapshot.id, contactTransferValues(snapshot.id, data, holderOf(env, data), definitions))\n }\n }\n }\n return out\n}\n\n/** A company link a row names: the company and its name, or `null` to unlink. */\ninterface CompanyLink {\n id: string | null\n name: string\n}\n\n/** Everything one apply call shares across its rows. */\ninterface ApplyRun {\n env: CrmTransferEnv\n hostId: string\n group: ConsentGroup\n actorUid: string | null\n definitions: ContactFieldDefinition[]\n companies: Map<string, Promise<{ id: string; name: string } | null>>\n admit: () => Promise<boolean>\n readContact: ReturnType<typeof cachedContactReader>\n}\n\n/** The company a row's company column names, resolved: an id the engine found, or one created by name. */\nasync function companyLinkFor(run: ApplyRun, value: unknown): Promise<CompanyLink> {\n if (value === null || value === undefined || value === '') return { id: null, name: '' }\n const create = transferLookupNewName(value)\n if (create) {\n const company = await companyForName(run.env, create, run.actorUid, run.companies, run.admit)\n if (!company) throw new TransferEngineError('invalid', 422, 'The CRM records limit has no room for the company.')\n return company\n }\n const snapshot = await run.env.orgRef.collection(CRM_COLLECTIONS.companies).doc(String(value)).get()\n if (!snapshot.exists || !visibleIn(run.env, snapshot.get('visibleTo'))) {\n throw new TransferEngineError('notFound', 404, 'The company this row names no longer exists.')\n }\n return { id: snapshot.id, name: textOf(snapshot.get('name')).slice(0, 120) }\n}\n\n/**\n * A row's values as the profile route's fields: each one normalized the way\n * that route reads it, a blank clearing it. Fields a value could not be\n * stored as are left out and named in `skipped`.\n */\nfunction profileFields(\n values: Readonly<Record<string, unknown>>,\n stored: ReturnType<typeof readContactFacet>,\n): { fields: ContactUpdateFields; skipped: string[] } {\n const fields: ContactUpdateFields = {}\n const skipped: string[] = []\n const text = (key: string, max = 120) => textOf(values[key]).slice(0, max)\n for (const key of ['jobTitle', 'department', 'assistantName', 'salutation', 'leadSource'] as const) {\n if (key in values) fields[key] = text(key)\n }\n if ('firstName' in values) fields.firstName = composeContactName(text('firstName'), '')\n if ('lastName' in values) fields.lastName = composeContactName('', text('lastName'))\n for (const key of ['phone', ...PHONE_FIELDS] as const) {\n if (!(key in values)) continue\n const typed = text(key, 40)\n const phone = typed ? normalizePhone(typed) : ''\n if (phone === null) skipped.push(key)\n else fields[key] = phone\n }\n if ('birthdate' in values) {\n const birthdate = normalizeContactBirthdate(text('birthdate', 20))\n if (birthdate === null) skipped.push('birthdate')\n else fields.birthdate = birthdate\n }\n if ('doNotCall' in values) fields.doNotCall = values['doNotCall'] === true\n if ('notes' in values) fields.notes = textOf(values['notes']).slice(0, CONTACT_NOTES_MAX)\n if ('tags' in values) fields.tags = Array.isArray(values['tags']) ? (values['tags'] as string[]).slice(0, 20) : []\n if ('owner' in values) fields.ownerUid = text('owner', 128)\n if ('reportsTo' in values) fields.reportsToContactId = text('reportsTo', 200) || null\n const mailing = addressFromValues('mailing', values, stored.address)\n if (mailing !== undefined) fields.address = mailing\n const other = addressFromValues('other', values, stored.otherAddress)\n if (other !== undefined) fields.otherAddress = other\n // The name follows the first and last names once either is set; only a\n // holder with neither keeps a name of its own.\n const composed = composeContactName(fields.firstName ?? stored.firstName, fields.lastName ?? stored.lastName)\n if ('name' in values && !composed) fields.name = text('name')\n return { fields, skipped }\n}\n\n/** The sentence a row's result carries for fields it could not store. */\nfunction skippedMessage(skipped: readonly string[]): string | undefined {\n if (!skipped.length) return undefined\n const labels = skipped.map((id) => CONTACT_TRANSFER_FIELDS.find((field) => field.id === id)?.label ?? id)\n return `Not written, as the value could not be read: ${labels.join(', ')}.`\n}\n\n/**\n * Writes one existing contact's values through the profile route's patch,\n * and the stage beside it. Answers the stage it replaced when it moved one,\n * and the fields left out.\n */\nasync function writeContact(\n run: ApplyRun,\n contactId: string,\n values: Readonly<Record<string, unknown>>,\n): Promise<{ skipped: string[] }> {\n const ref = contactsOf(run.env).doc(contactId)\n const snapshot = await ref.get()\n const contact = snapshot.data()\n if (!snapshot.exists || !contact || !visibleIn(run.env, contact['visibleTo'])) {\n throw new TransferEngineError('notFound', 404, 'That contact no longer exists.')\n }\n const groupId = run.group.groupId\n const stored = readContactFacet(contact, groupId)\n const { fields, skipped } = profileFields(values, stored)\n let linkedCompanyName = ''\n if ('company' in values) {\n const link = await companyLinkFor(run, values['company'])\n fields.companyId = link.id\n linkedCompanyName = link.name\n }\n if (fields.reportsToContactId) {\n const managerId = fields.reportsToContactId\n if (managerId === contactId) throw new TransferEngineError('invalid', 422, CONTACT_REPORTS_TO_SELF_REFUSAL)\n if (await contactReportsToLoops(run.readContact, contactId, managerId, groupId)) {\n throw new TransferEngineError('invalid', 422, CONTACT_REPORTS_TO_LOOP_REFUSAL)\n }\n }\n const custom = customWriteValues(values, run.definitions, 'contact')\n if ('error' in custom) throw new TransferEngineError('invalid', 422, custom.error)\n const patch = contactPatch(contact, groupId, fields, custom.values, linkedCompanyName)\n if ('refused' in patch) throw new TransferEngineError('invalid', 422, patch.refused)\n const update: Record<string, unknown> = { ...(patch.update ?? {}) }\n\n let movedFrom: string | null = null\n if ('lifecycleStage' in values) {\n const stage = crmLifecycleStageOf(values['lifecycleStage'])\n const previous = isContactLifecycleStage(stored.lifecycleStage) ? stored.lifecycleStage : ''\n if ((stage ?? '') !== previous) {\n update[contactFacetPath(groupId, 'lifecycleStage')] = stage ?? FieldValue.delete()\n if (stage) movedFrom = previous\n }\n }\n if (!Object.keys(update).length) return { skipped }\n update['updatedAt'] = FieldValue.serverTimestamp()\n await ref.update(update)\n await restampCrmListFieldsOf([ref], 'contacts')\n await settleCompanyCounts(run.env.orgRef.collection(CRM_COLLECTIONS.companies), [\n { contactId, ref, update, counts: patch.counts },\n ])\n if (movedFrom !== null) {\n await emitHostEvent(\n run.hostId,\n 'contactStageChanged',\n {\n contactId,\n email: textOf(contact['email']),\n lifecycleStage: String(crmLifecycleStageOf(values['lifecycleStage'])),\n previousStage: movedFrom,\n },\n run.actorUid ? { actor: { kind: 'member', uid: run.actorUid, email: null } } : {},\n ).catch((error: unknown) => console.error('[crm] transfer stage event failed', contactId, error))\n }\n return { skipped }\n}\n\n/** Creates one person through the capture door, then what the door does not take. */\nasync function createContact(\n run: ApplyRun,\n values: Readonly<Record<string, unknown>>,\n batch: Awaited<ReturnType<typeof prepareContactCaptureBatch>> | undefined,\n): Promise<{ contactId: string; created: boolean; skipped: string[] }> {\n const email = textOf(values['email'])\n const { fields, skipped } = profileFields(values, { sources: {}, interactions: [] })\n const link = 'company' in values ? await companyLinkFor(run, values['company']) : null\n const custom = customWriteValues(values, run.definitions, 'contact')\n if ('error' in custom) throw new TransferEngineError('invalid', 422, custom.error)\n const stage = crmLifecycleStageOf(values['lifecycleStage'])\n const verdict = await captureHostContact({\n hostId: run.hostId,\n email,\n ...(fields.name ? { name: fields.name } : {}),\n source: 'import',\n ...(run.actorUid ? { actor: { kind: 'member' as const, uid: run.actorUid, email: null } } : {}),\n interaction: { summary: CONTACT_TRANSFER_INTERACTION_SUMMARY },\n tags: fields.tags ?? [],\n facet: {\n ...(fields.phone ? { phone: fields.phone } : {}),\n ...(fields.jobTitle ? { jobTitle: fields.jobTitle } : {}),\n ...(fields.salutation ? { salutation: fields.salutation } : {}),\n ...(fields.firstName ? { firstName: fields.firstName } : {}),\n ...(fields.lastName ? { lastName: fields.lastName } : {}),\n ...(fields.department ? { department: fields.department } : {}),\n ...Object.fromEntries(PHONE_FIELDS.filter((key) => fields[key]).map((key) => [key, fields[key]])),\n ...(fields.birthdate ? { birthdate: fields.birthdate } : {}),\n ...(fields.assistantName ? { assistantName: fields.assistantName } : {}),\n ...(fields.leadSource ? { leadSource: fields.leadSource } : {}),\n ...(fields.doNotCall ? { doNotCall: true } : {}),\n ...(fields.address ? { address: fields.address } : {}),\n ...(fields.otherAddress ? { otherAddress: fields.otherAddress } : {}),\n // The link AND the name: the merge fields read the facet's name.\n ...(link?.id ? { companyId: link.id, companyName: link.name } : {}),\n ...(fields.ownerUid ? { ownerUid: fields.ownerUid } : {}),\n ...(stage ? { lifecycleStage: stage } : {}),\n ...(Object.keys(custom.values).length ? { custom: custom.values } : {}),\n },\n // An import files nobody under a campaign; the record's picker does.\n campaignIds: [],\n ...(batch ? { batch } : {}),\n })\n if ('refused' in verdict) {\n throw new TransferEngineError('invalid', 422, CAPTURE_REFUSALS[verdict.refused] ?? CAPTURE_REFUSALS['error'] as string)\n }\n // What the capture door does not write: who they report to, and the notes.\n const extra: Record<string, unknown> = {}\n if (fields.reportsToContactId) extra['reportsTo'] = fields.reportsToContactId\n if (fields.notes) extra['notes'] = fields.notes\n if (Object.keys(extra).length) await writeContact(run, verdict.contactId, extra)\n return { contactId: verdict.contactId, created: verdict.created, skipped }\n}\n\n/** The `crm.contacts` hooks. */\nexport function contactsTransferResource(): TransferRecordsHooks {\n return {\n async fields(ctx) {\n const env = await crmTransferEnv(ctx)\n return {\n standard: CONTACT_TRANSFER_FIELDS,\n derived: CONTACT_TRANSFER_DERIVED,\n system: CRM_TIMESTAMP_FIELDS,\n custom: crmCustomTransferFields(await crmCustomDefinitions(env, 'contact'), 'contact'),\n groups: CONTACT_TRANSFER_GROUPS,\n }\n },\n matchKeys: [\n { fieldId: TRANSFER_ID_FIELD, normalizer: 'aglynId' },\n { fieldId: 'email', normalizer: 'email' },\n ],\n aliases: CONTACT_ALIASES,\n lookupTargets: { [CRM_MEMBERS_TARGET]: crmMembersTarget() },\n\n // The people a workspace holds are its own on every plan (AGL-2839):\n // exporting them asks nothing of the plan.\n async count(ctx, options) {\n const env = await crmTransferEnv(ctx)\n return countCrmExport(env, contactsOf(env), options, (data) => visibleIn(env, data['visibleTo'], options.scopeTokens))\n },\n\n async readPage(ctx, cursor, fieldIds, options) {\n const env = await crmTransferEnv(ctx)\n const definitions = await crmCustomDefinitions(env, 'contact')\n const emails = fieldIds.includes('owner') ? await crmMemberEmails(env.orgId) : new Map<string, string>()\n return readCrmExportPage(\n env,\n contactsOf(env),\n cursor,\n options,\n (data) => visibleIn(env, data['visibleTo'], options?.scopeTokens),\n async (docs) => {\n const managers = new Map<string, string>()\n if (fieldIds.includes('reportsTo')) {\n const ids = [\n ...new Set(\n docs\n .map((doc) => textOf(readContactFacet(doc.data, holderOf(env, doc.data).groupId).reportsToContactId))\n .filter((id) => id && !id.includes('/')),\n ),\n ]\n for (let at = 0; at < ids.length; at += 500) {\n const page = ids.slice(at, at + 500)\n for (const snapshot of await env.firestore.getAll(...page.map((id) => contactsOf(env).doc(id)))) {\n if (snapshot.exists) managers.set(snapshot.id, textOf(snapshot.get('email')))\n }\n }\n }\n return docs.map((doc) =>\n pickValues(\n contactTransferValues(doc.id, doc.data, holderOf(env, doc.data), definitions, {\n owner: (uid) => emails.get(uid),\n manager: (id) => managers.get(id),\n }),\n fieldIds,\n ),\n )\n },\n )\n },\n\n async lookup(ctx, requests) {\n const env = await crmTransferEnv(ctx)\n const definitions = await crmCustomDefinitions(env, 'contact')\n const visible = (data: Record<string, unknown>) => visibleIn(env, data['visibleTo'])\n const found = { lookup: new Map<string, string[]>(), docs: new Map<string, Record<string, unknown>>() }\n for (const request of requests) {\n if (request.fieldId === TRANSFER_ID_FIELD) await lookupById(env, contactsOf(env), request, visible, found)\n else if (request.fieldId === 'email') {\n await lookupByField(contactsOf(env), request, 'email', (value) => value.trim().toLowerCase(), visible, found)\n }\n }\n return lookupResult(found, (id, data) => contactTransferValues(id, data, holderOf(env, data), definitions))\n },\n\n async suggest(ctx, request) {\n const env = await crmTransferEnv(ctx)\n const answer: Record<string, ReturnType<typeof rankTransferLookupSuggestions>> = {}\n for (const value of request.values) {\n // People sharing the value's first word: the token the list's own\n // search reads, so a mistyped domain still finds the person.\n const word = value.trim().toLowerCase().split(/[\\s@.+_-]+/)[0]?.slice(0, 12) ?? ''\n if (word.length < 2) {\n answer[value] = []\n continue\n }\n const snapshot = await contactsOf(env).where('searchTokens', 'array-contains', word).limit(IN_LIMIT).get()\n const candidates = snapshot.docs\n .filter((doc) => visibleIn(env, doc.get('visibleTo')))\n .flatMap((doc) => {\n const email = textOf(doc.get('email'))\n return email ? [{ recordId: doc.id, label: email }] : []\n })\n answer[value] = rankTransferLookupSuggestions(value, candidates)\n }\n return answer\n },\n\n async picklists(ctx, ids) {\n const env = await crmTransferEnv(ctx)\n return crmPicklistLists(env, ids, await crmCustomDefinitions(env, 'contact'))\n },\n\n async addPicklistValues(ctx, picklistId, values) {\n await addCrmPicklistValues(await crmTransferEnv(ctx), picklistId, values)\n },\n\n lockedRules: () => [\n {\n fieldId: 'email',\n reason: 'An existing contact’s email is who they are; change it on the contact’s page.',\n forced: { mode: 'keepExisting' },\n },\n {\n fieldId: 'marketingConsent',\n reason:\n 'Consent is never taken from a file: a person gives it on a form, or a team member records how it was given on the contact’s page.',\n refuseValues: true,\n },\n {\n fieldId: 'lifecycleStage',\n reason: 'A stage moves forward only: a later stage in the file advances the contact, an earlier one is held back.',\n forced: { mode: 'overwrite' },\n },\n {\n fieldId: 'doNotCall',\n reason: 'A file can say a person asked not to be called, never that they took it back.',\n forced: { mode: 'overwrite' },\n },\n {\n fieldId: 'name',\n reason: 'The full name is built from the first and last names once either is set.',\n },\n ],\n\n async plan(ctx, input) {\n const env = await crmTransferEnv(ctx)\n requireCrmSuite(env, SUITE_ACT)\n requireSite(env, 'contacts')\n const plan = buildTransferPlan(input)\n return holdBackChanges(plan, (row, change) => {\n const before = row.recordId ? input.existing.get(row.recordId) : undefined\n if (change.fieldId === 'lifecycleStage' && before) {\n const from = crmLifecycleStageRank(before['lifecycleStage'])\n const to = crmLifecycleStageRank(change.after)\n if (from >= 0 && (to < from || to < 0)) return 'A stage moves forward only.'\n }\n if (change.fieldId === 'doNotCall' && before?.['doNotCall'] === true && change.after !== true) {\n return 'Do not call is turned off on the contact’s page, never by a file.'\n }\n if (change.fieldId === 'name') {\n const values = Object.fromEntries(row.diff.map((entry) => [entry.fieldId, entry.after]))\n const first = 'firstName' in values ? values['firstName'] : before?.['firstName']\n const last = 'lastName' in values ? values['lastName'] : before?.['lastName']\n if (textOf(first) || textOf(last)) return 'Built from the first and last names.'\n }\n return null\n })\n },\n\n async apply(ctx, chunk, writer) {\n const env = await crmTransferEnv(ctx)\n requireCrmSuite(env, SUITE_ACT)\n const { hostId, group } = requireSite(env, 'contacts')\n const run: ApplyRun = {\n env,\n hostId,\n group,\n actorUid: ctx.actorUid,\n definitions: await crmCustomDefinitions(env, 'contact'),\n companies: new Map(),\n admit: crmRecordsRoom(env),\n readContact: cachedContactReader(contactsOf(env)),\n }\n const rows = chunk.rows as PlannedTransferRow[]\n const creating: string[] = []\n for (const row of rows) {\n if (row.verdict === 'create' && !(await writer.alreadyApplied(row.index))) {\n const email = textOf(plannedValues(row)['email'])\n if (email) creating.push(email)\n }\n }\n // The capture door's lookups for every new person at once (AGL-3423).\n const batch = creating.length ? await prepareContactCaptureBatch(hostId, creating) : undefined\n const results: TransferRowResult[] = []\n const undo: TransferUndoEntry[] = []\n\n await eachWithinBudget(rows, () => writer.timeLeftMs(), async (row) => {\n const earlier = await writer.alreadyApplied(row.index)\n if (earlier) {\n results.push(earlier)\n return\n }\n const changed = row.diff.map((change) => change.fieldId)\n let result: TransferRowResult\n let entry: TransferUndoEntry | undefined\n try {\n const values = plannedValues(row)\n if (row.verdict === 'update' && row.recordId) {\n const before = (await readContacts(env, [row.recordId], run.definitions)).get(row.recordId)\n if (!before) throw new TransferEngineError('notFound', 404, 'That contact no longer exists.')\n const { skipped } = await writeContact(run, row.recordId, values)\n const after = (await readContacts(env, [row.recordId], run.definitions)).get(row.recordId) ?? {}\n const message = skippedMessage(skipped)\n result = { row: row.index, outcome: 'updated', recordId: row.recordId, ...(message ? { message } : {}) }\n entry = {\n row: row.index,\n recordId: row.recordId,\n action: 'updated',\n previous: pickValues(before, changed),\n written: pickValues(after, changed),\n }\n } else {\n const made = await createContact(run, values, batch)\n const after = (await readContacts(env, [made.contactId], run.definitions)).get(made.contactId) ?? {}\n const message = made.created\n ? skippedMessage(made.skipped)\n : 'Merged into the contact already holding this email.'\n result = {\n row: row.index,\n outcome: made.created ? 'created' : 'updated',\n recordId: made.contactId,\n ...(message ? { message } : {}),\n }\n // A merge into a person somebody else created meanwhile has no\n // \"before\" to put back, so undo leaves it alone.\n entry = made.created\n ? { row: row.index, recordId: made.contactId, action: 'created', written: pickValues(after, changed) }\n : undefined\n }\n } catch (error) {\n result = {\n row: row.index,\n outcome: 'failed',\n ...(row.recordId ? { recordId: row.recordId } : {}),\n message: failureMessage(error),\n }\n entry = undefined\n }\n await writer.markApplied(result, entry)\n results.push(result)\n if (entry) undo.push(entry)\n })\n return { results, undo }\n },\n\n async revert(ctx, snapshot, decisions) {\n const env = await crmTransferEnv(ctx)\n const { hostId, group } = requireSite(env, 'contacts')\n const run: ApplyRun = {\n env,\n hostId,\n group,\n actorUid: ctx.actorUid,\n definitions: await crmCustomDefinitions(env, 'contact'),\n companies: new Map(),\n admit: crmRecordsRoom(env),\n readContact: cachedContactReader(contactsOf(env)),\n }\n const current = await readContacts(env, snapshot.entries.map((entry) => entry.recordId), run.definitions)\n const done: TransferUndoStep[] = []\n const conflicts: TransferUndoStep[] = []\n for (const entry of snapshot.entries) {\n const step = planTransferUndo(entry, current.get(entry.recordId) ?? null)\n if (step.action === 'conflict' && decisions?.[entry.recordId] !== 'revert') {\n if (decisions?.[entry.recordId] === 'keep') done.push({ action: 'nothing', recordId: entry.recordId, why: 'alreadyReverted' })\n else conflicts.push(step)\n continue\n }\n if (step.action === 'nothing') {\n done.push(step)\n continue\n }\n if (entry.action === 'created') {\n // The site lets the person go, as \"Remove from this site\" does: a\n // person only this import's site held is deleted, keeping every\n // refusal they made; one another site holds too stays theirs.\n const contactRef = contactsOf(env).doc(entry.recordId)\n let holders: string[] = []\n const removal = await removeContactKeepingRefusals({\n contactRef,\n decide: (contact) => {\n holders = contactFacetHolders(contact)\n return planContactDetach(contact, group)\n },\n nowMs: Date.now(),\n })\n if (removal.outcome === 'deleted') {\n await clearReportsToOf(env.firestore, contactsOf(env), holders, entry.recordId)\n await sweepDealContactRoles(\n env.firestore,\n env.orgRef.collection(CRM_COLLECTIONS.deals),\n entry.recordId,\n null,\n '[crm] transfer undo',\n )\n } else if (removal.outcome === 'detached') {\n await clearReportsToOf(env.firestore, contactsOf(env), [group.groupId], entry.recordId)\n await restampCrmListFieldsOf([contactRef], 'contacts').catch(() => undefined)\n }\n done.push({ action: 'delete', recordId: entry.recordId })\n continue\n }\n const values = step.action === 'restore' || step.action === 'conflict' ? step.values : {}\n await writeContact(run, entry.recordId, values)\n done.push(step)\n }\n return { done, conflicts }\n },\n }\n}\n"],"names":["composeContactName","contactDisplayName","contactFacetPath","CRM_COLLECTIONS","interactionsForGroup","isContactLifecycleStage","normalizeContactBirthdate","normalizePhone","planContactDetach","readContactFacet","readMarketingBasis","CONTACT_LIFECYCLE_STAGE_LABELS","CONTACT_EXTRA_PHONE_FIELDS","PHONE_FIELDS","buildTransferPlan","planTransferUndo","rankTransferLookupSuggestions","TRANSFER_ID_FIELD","transferLookupNewName","prepareContactCaptureBatch","removeContactKeepingRefusals","restampCrmListFieldsOf","emitHostEvent","FieldValue","contactPrimaryGroup","captureHostContact","CONTACT_NOTES_MAX","cachedContactReader","clearReportsToOf","CONTACT_REPORTS_TO_LOOP_REFUSAL","CONTACT_REPORTS_TO_SELF_REFUSAL","contactFacetHolders","contactReportsToLoops","contactPatch","settleCompanyCounts","sweepDealContactRoles","CONTACT_ALIASES","addCrmPicklistValues","addressFromValues","addressValues","countCrmExport","crmCustomDefinitions","crmMemberEmails","crmMembersTarget","crmPicklistLists","crmRecordsRoom","crmTransferEnv","customTransferValues","customWriteValues","eachWithinBudget","failureMessage","holdBackChanges","IN_LIMIT","isoOf","lookupByField","lookupById","lookupResult","pickValues","plannedValues","readCrmExportPage","requireCrmSuite","requireSite","textOf","TransferEngineError","visibleIn","companyForName","CONTACT_TRANSFER_DERIVED","CONTACT_TRANSFER_FIELDS","CONTACT_TRANSFER_GROUPS","CRM_MEMBERS_TARGET","CRM_TIMESTAMP_FIELDS","crmCustomTransferFields","crmLifecycleStageOf","crmLifecycleStageRank","CONTACT_TRANSFER_INTERACTION_SUMMARY","SUITE_ACT","contactsOf","env","orgRef","collection","holderOf","contact","group","org","CAPTURE_REFUSALS","band","erased","error","contactTransferValues","id","definitions","names","facet","groupId","text","value","stage","lifecycleStage","basis","ownerUid","managerId","reportsToContactId","name","email","salutation","firstName","lastName","birthdate","phone","mobilePhone","homePhone","otherPhone","fax","doNotCall","assistantName","assistantPhone","jobTitle","department","company","companyName","companyId","reportsTo","manager","address","otherAddress","owner","leadSource","tags","Array","isArray","notes","marketingConsent","sources","Object","keys","lastInteractionAt","interactions","hostIds","atMs","lastEngagedAt","lastEmailEngagementAtMs","createdAt","updatedAt","custom","readContacts","ids","out","Map","at","length","page","slice","filter","includes","snapshot","firestore","getAll","map","doc","data","exists","set","companyLinkFor","run","undefined","create","actorUid","companies","admit","String","get","profileFields","values","stored","fields","skipped","key","max","typed","push","mailing","other","composed","skippedMessage","labels","find","field","label","join","writeContact","contactId","patch","ref","linkedCompanyName","link","readContact","refused","update","movedFrom","previous","delete","serverTimestamp","counts","hostId","previousStage","actor","kind","uid","catch","console","createContact","batch","verdict","source","interaction","summary","fromEntries","campaignIds","extra","created","contactsTransferResource","ctx","standard","derived","system","groups","matchKeys","fieldId","normalizer","aliases","lookupTargets","count","options","scopeTokens","readPage","cursor","fieldIds","emails","orgId","docs","managers","Set","lookup","requests","visible","found","request","trim","toLowerCase","suggest","answer","word","split","where","limit","candidates","flatMap","recordId","picklists","addPicklistValues","picklistId","lockedRules","reason","forced","mode","refuseValues","plan","input","row","change","before","existing","from","to","after","diff","entry","first","last","apply","chunk","writer","rows","creating","alreadyApplied","index","results","undo","timeLeftMs","earlier","changed","result","message","outcome","action","written","made","markApplied","revert","decisions","current","entries","done","conflicts","step","why","contactRef","holders","removal","decide","nowMs","Date","now","deals"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/transfer/contacts.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * CONTACTS ON THE TRANSFER FRAMEWORK (AGL-3527) — the server half of\n * `crm.contacts`.\n *\n * A contact is one person shared by every site of the workspace, and each\n * site's consent group keeps its own profile of them — its facet. So a\n * transfer reads and writes the facet of the site it was opened under: an\n * export at the organization level reads each person's primary holder, as\n * the org-level list does; an import always names a site, because a\n * contact is a person some site met.\n *\n * ## The writes are the CRM's own\n *\n * A new person goes through `captureHostContact`, the door every capture\n * goes through — the records band, the erasure check, the consent group's\n * facet, `contactCreated` for the automations, the company by the email's\n * domain and the owner by the assignment rules when the row names neither.\n * A matched person is changed through the contact profile route's own\n * patch (`contactPatch`): the composed name, the company link and its\n * contact counts, the list's filter keys. A stage that moves raises\n * `contactStageChanged`, as the stage route does.\n *\n * ## What a file may not do\n *\n * The locked rules: an existing contact's email is who they are; consent is\n * never taken from a file; a stage moves forward only; Do not call is\n * turned on by a file and never off; the full name follows the first and\n * last names once either is set. The plan holds each one back by row and\n * names it, so the person acknowledges it before anything is written.\n *=========================================*/\n\nimport {\n composeContactName,\n type ConsentGroup,\n crmDefaultScopeOf,\n ORG_CONTACT_HOLDER_ID,\n contactDisplayName,\n contactFacetPath,\n type ContactFieldDefinition,\n CRM_COLLECTIONS,\n interactionsForGroup,\n isContactLifecycleStage,\n normalizeContactBirthdate,\n normalizePhone,\n planContactDetach,\n readContactFacet,\n readMarketingBasis,\n} from '@aglyn/aglyn/server'\nimport { CONTACT_LIFECYCLE_STAGE_LABELS } from '@aglyn/aglyn/app-utils/crm'\nimport { CONTACT_EXTRA_PHONE_FIELDS as PHONE_FIELDS } from '@aglyn/aglyn/app-utils/contacts'\nimport {\n buildTransferPlan,\n planTransferUndo,\n rankTransferLookupSuggestions,\n TRANSFER_ID_FIELD,\n transferLookupNewName,\n type PlannedTransferRow,\n type TransferRowResult,\n type TransferUndoEntry,\n type TransferUndoStep,\n} from '@aglyn/aglyn/data-transfer'\nimport type { TransferRecordsHooks } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\nimport {\n prepareContactCaptureBatch,\n removeContactKeepingRefusals,\n restampCrmListFieldsOf,\n} from '@aglyn/tenant-data-admin'\nimport { emitHostEvent } from '@aglyn/tenant-runtime'\nimport { FieldValue } from 'firebase-admin/firestore'\nimport { contactPrimaryGroup, ORG_HOLDER_GROUP } from '../model/contact-holder'\nimport type { ContactUpdateFields } from '../model/contact-update'\nimport { captureHostContact } from '../server/capture-host-contact'\nimport { CONTACT_NOTES_MAX } from '../server/contact-profile'\nimport {\n cachedContactReader,\n clearReportsToOf,\n CONTACT_REPORTS_TO_LOOP_REFUSAL,\n CONTACT_REPORTS_TO_SELF_REFUSAL,\n contactFacetHolders,\n contactReportsToLoops,\n} from '../server/contact-reports-to'\nimport { contactPatch, settleCompanyCounts } from '../server/contact-update'\nimport { sweepDealContactRoles } from '../server/deal-contact-roles'\nimport { CONTACT_ALIASES } from './aliases'\nimport {\n addCrmPicklistValues,\n addressFromValues,\n addressValues,\n countCrmExport,\n crmCustomDefinitions,\n crmMemberEmails,\n crmMembersTarget,\n crmPicklistLists,\n crmRecordsRoom,\n crmTransferEnv,\n type CrmTransferEnv,\n customTransferValues,\n customWriteValues,\n eachWithinBudget,\n failureMessage,\n holdBackChanges,\n IN_LIMIT,\n isoOf,\n lookupByField,\n lookupById,\n lookupResult,\n pickValues,\n plannedValues,\n readCrmExportPage,\n requireCrmSuite,\n requireSite,\n textOf,\n TransferEngineError,\n visibleIn,\n} from './common'\nimport { companyForName } from './companies'\nimport { addContactByHand } from '../server/add-contact-by-hand'\nimport {\n CONTACT_TRANSFER_DERIVED,\n CONTACT_TRANSFER_FIELDS,\n CONTACT_TRANSFER_GROUPS,\n CRM_MEMBERS_TARGET,\n CRM_TIMESTAMP_FIELDS,\n crmCustomTransferFields,\n crmLifecycleStageOf,\n crmLifecycleStageRank,\n} from './fields'\n\n/** The sentence an imported person's timeline opens with. */\nexport const CONTACT_TRANSFER_INTERACTION_SUMMARY = 'Imported from a file'\n\nconst SUITE_ACT = 'Importing contacts'\n\nconst contactsOf = (env: CrmTransferEnv) => env.orgRef.collection('contacts')\n\n/** The holder a contact is read through: the site's group, else the person's primary holder. */\nfunction holderOf(env: CrmTransferEnv, contact: Record<string, unknown>): ConsentGroup {\n return env.group ?? contactPrimaryGroup(contact, env.org)\n}\n\n/** Why a capture refused a person, in the result's words. */\nconst CAPTURE_REFUSALS: Readonly<Record<string, string>> = {\n band: 'The contact limit is reached.',\n 'invalid-email': 'Not a valid email address.',\n erased: 'Erased from this workspace at their request.',\n error: 'The contact could not be saved.',\n}\n\n/**\n * One contact as values by field id, read through one holder's facet. A\n * lookup and an undo read links by id (`ids`), so the plan compares what is\n * stored; an export writes names a file can carry back (`names`).\n */\nexport function contactTransferValues(\n id: string,\n contact: Record<string, unknown>,\n group: ConsentGroup,\n definitions: readonly ContactFieldDefinition[],\n names?: { owner: (uid: string) => string | undefined; manager: (id: string) => string | undefined },\n): Record<string, unknown> {\n const facet = readContactFacet(contact, group.groupId)\n const text = (value: unknown) => textOf(value) || null\n const stage = isContactLifecycleStage(facet.lifecycleStage) ? CONTACT_LIFECYCLE_STAGE_LABELS[facet.lifecycleStage] : null\n const basis = group.groupId ? readMarketingBasis(contact, group).basis : 'unrecorded'\n const ownerUid = text(facet.ownerUid)\n const managerId = text(facet.reportsToContactId)\n return {\n // The name first: a record's label is the first text it holds.\n name: text(contactDisplayName(contact, group.groupId)),\n email: text(contact['email']),\n salutation: text(facet.salutation),\n firstName: text(facet.firstName),\n lastName: text(facet.lastName),\n birthdate: text(facet.birthdate),\n phone: text(facet.phone),\n mobilePhone: text(facet.mobilePhone),\n homePhone: text(facet.homePhone),\n otherPhone: text(facet.otherPhone),\n fax: text(facet.fax),\n doNotCall: facet.doNotCall === true,\n assistantName: text(facet.assistantName),\n assistantPhone: text(facet.assistantPhone),\n jobTitle: text(facet.jobTitle),\n department: text(facet.department),\n company: names ? text(facet.companyName) : text(facet.companyId),\n reportsTo: managerId ? (names ? (names.manager(managerId) ?? managerId) : managerId) : null,\n ...addressValues('mailing', facet.address),\n ...addressValues('other', facet.otherAddress),\n owner: ownerUid ? (names ? (names.owner(ownerUid) ?? ownerUid) : ownerUid) : null,\n lifecycleStage: stage,\n leadSource: text(facet.leadSource),\n tags: Array.isArray(facet.tags) ? facet.tags : [],\n notes: text(facet.notes),\n marketingConsent: basis === 'granted' ? true : basis === 'declined' ? false : null,\n sources: Object.keys(facet.sources ?? {}),\n lastInteractionAt: isoOf(interactionsForGroup(facet.interactions, group.hostIds)[0]?.atMs),\n lastEngagedAt: isoOf(facet.lastEmailEngagementAtMs),\n createdAt: isoOf(contact['createdAt']),\n updatedAt: isoOf(contact['updatedAt']),\n ...customTransferValues(definitions, facet.custom),\n [TRANSFER_ID_FIELD]: id,\n }\n}\n\n/** The contacts these ids name, as values through the site's facet. */\nasync function readContacts(\n env: CrmTransferEnv,\n ids: readonly string[],\n definitions: readonly ContactFieldDefinition[],\n): Promise<Map<string, Record<string, unknown>>> {\n const out = new Map<string, Record<string, unknown>>()\n for (let at = 0; at < ids.length; at += 500) {\n const page = ids.slice(at, at + 500).filter((id) => id && !id.includes('/'))\n if (!page.length) continue\n for (const snapshot of await env.firestore.getAll(...page.map((id) => contactsOf(env).doc(id)))) {\n const data = snapshot.data()\n if (snapshot.exists && data && visibleIn(env, data['visibleTo'])) {\n out.set(snapshot.id, contactTransferValues(snapshot.id, data, holderOf(env, data), definitions))\n }\n }\n }\n return out\n}\n\n/** A company link a row names: the company and its name, or `null` to unlink. */\ninterface CompanyLink {\n id: string | null\n name: string\n}\n\n/** Everything one apply call shares across its rows. */\ninterface ApplyRun {\n env: CrmTransferEnv\n /** The Source site, or `null` for a file with none (AGL-4122). */\n hostId: string | null\n group: ConsentGroup\n actorUid: string | null\n definitions: ContactFieldDefinition[]\n companies: Map<string, Promise<{ id: string; name: string } | null>>\n admit: () => Promise<boolean>\n readContact: ReturnType<typeof cachedContactReader>\n}\n\n/** The company a row's company column names, resolved: an id the engine found, or one created by name. */\nasync function companyLinkFor(run: ApplyRun, value: unknown): Promise<CompanyLink> {\n if (value === null || value === undefined || value === '') return { id: null, name: '' }\n const create = transferLookupNewName(value)\n if (create) {\n const company = await companyForName(run.env, create, run.actorUid, run.companies, run.admit)\n if (!company) throw new TransferEngineError('invalid', 422, 'The CRM records limit has no room for the company.')\n return company\n }\n const snapshot = await run.env.orgRef.collection(CRM_COLLECTIONS.companies).doc(String(value)).get()\n if (!snapshot.exists || !visibleIn(run.env, snapshot.get('visibleTo'))) {\n throw new TransferEngineError('notFound', 404, 'The company this row names no longer exists.')\n }\n return { id: snapshot.id, name: textOf(snapshot.get('name')).slice(0, 120) }\n}\n\n/**\n * A row's values as the profile route's fields: each one normalized the way\n * that route reads it, a blank clearing it. Fields a value could not be\n * stored as are left out and named in `skipped`.\n */\nfunction profileFields(\n values: Readonly<Record<string, unknown>>,\n stored: ReturnType<typeof readContactFacet>,\n): { fields: ContactUpdateFields; skipped: string[] } {\n const fields: ContactUpdateFields = {}\n const skipped: string[] = []\n const text = (key: string, max = 120) => textOf(values[key]).slice(0, max)\n for (const key of ['jobTitle', 'department', 'assistantName', 'salutation', 'leadSource'] as const) {\n if (key in values) fields[key] = text(key)\n }\n if ('firstName' in values) fields.firstName = composeContactName(text('firstName'), '')\n if ('lastName' in values) fields.lastName = composeContactName('', text('lastName'))\n for (const key of ['phone', ...PHONE_FIELDS] as const) {\n if (!(key in values)) continue\n const typed = text(key, 40)\n const phone = typed ? normalizePhone(typed) : ''\n if (phone === null) skipped.push(key)\n else fields[key] = phone\n }\n if ('birthdate' in values) {\n const birthdate = normalizeContactBirthdate(text('birthdate', 20))\n if (birthdate === null) skipped.push('birthdate')\n else fields.birthdate = birthdate\n }\n if ('doNotCall' in values) fields.doNotCall = values['doNotCall'] === true\n if ('notes' in values) fields.notes = textOf(values['notes']).slice(0, CONTACT_NOTES_MAX)\n if ('tags' in values) fields.tags = Array.isArray(values['tags']) ? (values['tags'] as string[]).slice(0, 20) : []\n if ('owner' in values) fields.ownerUid = text('owner', 128)\n if ('reportsTo' in values) fields.reportsToContactId = text('reportsTo', 200) || null\n const mailing = addressFromValues('mailing', values, stored.address)\n if (mailing !== undefined) fields.address = mailing\n const other = addressFromValues('other', values, stored.otherAddress)\n if (other !== undefined) fields.otherAddress = other\n // The name follows the first and last names once either is set; only a\n // holder with neither keeps a name of its own.\n const composed = composeContactName(fields.firstName ?? stored.firstName, fields.lastName ?? stored.lastName)\n if ('name' in values && !composed) fields.name = text('name')\n return { fields, skipped }\n}\n\n/** The sentence a row's result carries for fields it could not store. */\nfunction skippedMessage(skipped: readonly string[]): string | undefined {\n if (!skipped.length) return undefined\n const labels = skipped.map((id) => CONTACT_TRANSFER_FIELDS.find((field) => field.id === id)?.label ?? id)\n return `Not written, as the value could not be read: ${labels.join(', ')}.`\n}\n\n/**\n * Writes one existing contact's values through the profile route's patch,\n * and the stage beside it. Answers the stage it replaced when it moved one,\n * and the fields left out.\n */\nasync function writeContact(\n run: ApplyRun,\n contactId: string,\n values: Readonly<Record<string, unknown>>,\n): Promise<{ skipped: string[] }> {\n const ref = contactsOf(run.env).doc(contactId)\n const snapshot = await ref.get()\n const contact = snapshot.data()\n if (!snapshot.exists || !contact || !visibleIn(run.env, contact['visibleTo'])) {\n throw new TransferEngineError('notFound', 404, 'That contact no longer exists.')\n }\n // With no site the row is written to the holder the person already has.\n const groupId =\n (run.hostId ? run.group : contactPrimaryGroup(contact, run.env.org)).groupId ||\n ORG_CONTACT_HOLDER_ID\n const stored = readContactFacet(contact, groupId)\n const { fields, skipped } = profileFields(values, stored)\n let linkedCompanyName = ''\n if ('company' in values) {\n const link = await companyLinkFor(run, values['company'])\n fields.companyId = link.id\n linkedCompanyName = link.name\n }\n if (fields.reportsToContactId) {\n const managerId = fields.reportsToContactId\n if (managerId === contactId) throw new TransferEngineError('invalid', 422, CONTACT_REPORTS_TO_SELF_REFUSAL)\n if (await contactReportsToLoops(run.readContact, contactId, managerId, groupId)) {\n throw new TransferEngineError('invalid', 422, CONTACT_REPORTS_TO_LOOP_REFUSAL)\n }\n }\n const custom = customWriteValues(values, run.definitions, 'contact')\n if ('error' in custom) throw new TransferEngineError('invalid', 422, custom.error)\n const patch = contactPatch(contact, groupId, fields, custom.values, linkedCompanyName)\n if ('refused' in patch) throw new TransferEngineError('invalid', 422, patch.refused)\n const update: Record<string, unknown> = { ...(patch.update ?? {}) }\n\n let movedFrom: string | null = null\n if ('lifecycleStage' in values) {\n const stage = crmLifecycleStageOf(values['lifecycleStage'])\n const previous = isContactLifecycleStage(stored.lifecycleStage) ? stored.lifecycleStage : ''\n if ((stage ?? '') !== previous) {\n update[contactFacetPath(groupId, 'lifecycleStage')] = stage ?? FieldValue.delete()\n if (stage) movedFrom = previous\n }\n }\n if (!Object.keys(update).length) return { skipped }\n update['updatedAt'] = FieldValue.serverTimestamp()\n await ref.update(update)\n await restampCrmListFieldsOf([ref], 'contacts')\n await settleCompanyCounts(run.env.orgRef.collection(CRM_COLLECTIONS.companies), [\n { contactId, ref, update, counts: patch.counts },\n ])\n if (movedFrom !== null && run.hostId) {\n await emitHostEvent(\n run.hostId,\n 'contactStageChanged',\n {\n contactId,\n email: textOf(contact['email']),\n lifecycleStage: String(crmLifecycleStageOf(values['lifecycleStage'])),\n previousStage: movedFrom,\n },\n run.actorUid ? { actor: { kind: 'member', uid: run.actorUid, email: null } } : {},\n ).catch((error: unknown) => console.error('[crm] transfer stage event failed', contactId, error))\n }\n return { skipped }\n}\n\n/**\n * The site a contact import is filed under. None, when the org's records belong\n * to every site (AGL-4122): the file then has no Source site, and the people in\n * it are the organization's. An org that keeps its sites apart must name one.\n */\nfunction contactImportSite(env: CrmTransferEnv): { hostId: string | null; group: ConsentGroup } {\n if (!env.hostId && crmDefaultScopeOf(env.org) === 'org') {\n return { hostId: null, group: ORG_HOLDER_GROUP }\n }\n return requireSite(env, 'contacts')\n}\n\n/** Creates one person through the capture door, then what the door does not take. */\nasync function createContact(\n run: ApplyRun,\n values: Readonly<Record<string, unknown>>,\n batch: Awaited<ReturnType<typeof prepareContactCaptureBatch>> | undefined,\n): Promise<{ contactId: string; created: boolean; skipped: string[] }> {\n const email = textOf(values['email'])\n const { fields, skipped } = profileFields(values, { sources: {}, interactions: [] })\n const link = 'company' in values ? await companyLinkFor(run, values['company']) : null\n const custom = customWriteValues(values, run.definitions, 'contact')\n if ('error' in custom) throw new TransferEngineError('invalid', 422, custom.error)\n const stage = crmLifecycleStageOf(values['lifecycleStage'])\n const facet = {\n ...(fields.phone ? { phone: fields.phone } : {}),\n ...(fields.jobTitle ? { jobTitle: fields.jobTitle } : {}),\n ...(fields.salutation ? { salutation: fields.salutation } : {}),\n ...(fields.firstName ? { firstName: fields.firstName } : {}),\n ...(fields.lastName ? { lastName: fields.lastName } : {}),\n ...(fields.department ? { department: fields.department } : {}),\n ...Object.fromEntries(PHONE_FIELDS.filter((key) => fields[key]).map((key) => [key, fields[key]])),\n ...(fields.birthdate ? { birthdate: fields.birthdate } : {}),\n ...(fields.assistantName ? { assistantName: fields.assistantName } : {}),\n ...(fields.leadSource ? { leadSource: fields.leadSource } : {}),\n ...(fields.doNotCall ? { doNotCall: true } : {}),\n ...(fields.address ? { address: fields.address } : {}),\n ...(fields.otherAddress ? { otherAddress: fields.otherAddress } : {}),\n // The link AND the name: the merge fields read the facet's name.\n ...(link?.id ? { companyId: link.id, companyName: link.name } : {}),\n ...(fields.ownerUid ? { ownerUid: fields.ownerUid } : {}),\n ...(Object.keys(custom.values).length ? { custom: custom.values } : {}),\n }\n const staged = stage ? { lifecycleStage: stage } : {}\n /*\n * A SITE AND AN ADDRESS ARE A CAPTURE. Anything less is a person no capture\n * door could take, so a file can hold people with no email and be imported\n * with no site (AGL-4122). A row still has to say who it is about.\n */\n if (!email && !fields.name && !facet.phone && !facet.firstName && !facet.lastName && !fields['mobilePhone']) {\n throw new TransferEngineError('invalid', 422, 'A row needs a name, an email or a phone number.')\n }\n const verdict =\n run.hostId && email\n ? await captureHostContact({\n hostId: run.hostId,\n email,\n ...(fields.name ? { name: fields.name } : {}),\n source: 'import',\n ...(run.actorUid\n ? { actor: { kind: 'member' as const, uid: run.actorUid, email: null } }\n : {}),\n interaction: { summary: CONTACT_TRANSFER_INTERACTION_SUMMARY },\n tags: fields.tags ?? [],\n // The file's own stage, or none: `lifecycleStage` from the column.\n facet: { ...facet, ...staged },\n // An import files nobody under a campaign; the record's picker does.\n campaignIds: [],\n ...(batch ? { batch } : {}),\n })\n : await addContactByHand({\n orgId: run.env.orgId,\n org: run.env.org,\n sourceHostId: run.hostId,\n email: email || null,\n ...(fields.name ? { name: fields.name } : {}),\n facet: { ...facet, ...staged },\n tags: fields.tags ?? [],\n })\n if ('refused' in verdict) {\n throw new TransferEngineError('invalid', 422, CAPTURE_REFUSALS[verdict.refused] ?? CAPTURE_REFUSALS['error'] as string)\n }\n // What the capture door does not write: who they report to, and the notes.\n const extra: Record<string, unknown> = {}\n if (fields.reportsToContactId) extra['reportsTo'] = fields.reportsToContactId\n if (fields.notes) extra['notes'] = fields.notes\n if (Object.keys(extra).length) await writeContact(run, verdict.contactId, extra)\n return { contactId: verdict.contactId, created: verdict.created, skipped }\n}\n\n/** The `crm.contacts` hooks. */\nexport function contactsTransferResource(): TransferRecordsHooks {\n return {\n async fields(ctx) {\n const env = await crmTransferEnv(ctx)\n return {\n standard: CONTACT_TRANSFER_FIELDS,\n derived: CONTACT_TRANSFER_DERIVED,\n system: CRM_TIMESTAMP_FIELDS,\n custom: crmCustomTransferFields(await crmCustomDefinitions(env, 'contact'), 'contact'),\n groups: CONTACT_TRANSFER_GROUPS,\n }\n },\n matchKeys: [\n { fieldId: TRANSFER_ID_FIELD, normalizer: 'aglynId' },\n { fieldId: 'email', normalizer: 'email' },\n ],\n aliases: CONTACT_ALIASES,\n lookupTargets: { [CRM_MEMBERS_TARGET]: crmMembersTarget() },\n\n // The people a workspace holds are its own on every plan (AGL-2839):\n // exporting them asks nothing of the plan.\n async count(ctx, options) {\n const env = await crmTransferEnv(ctx)\n return countCrmExport(env, contactsOf(env), options, (data) => visibleIn(env, data['visibleTo'], options.scopeTokens))\n },\n\n async readPage(ctx, cursor, fieldIds, options) {\n const env = await crmTransferEnv(ctx)\n const definitions = await crmCustomDefinitions(env, 'contact')\n const emails = fieldIds.includes('owner') ? await crmMemberEmails(env.orgId) : new Map<string, string>()\n return readCrmExportPage(\n env,\n contactsOf(env),\n cursor,\n options,\n (data) => visibleIn(env, data['visibleTo'], options?.scopeTokens),\n async (docs) => {\n const managers = new Map<string, string>()\n if (fieldIds.includes('reportsTo')) {\n const ids = [\n ...new Set(\n docs\n .map((doc) => textOf(readContactFacet(doc.data, holderOf(env, doc.data).groupId).reportsToContactId))\n .filter((id) => id && !id.includes('/')),\n ),\n ]\n for (let at = 0; at < ids.length; at += 500) {\n const page = ids.slice(at, at + 500)\n for (const snapshot of await env.firestore.getAll(...page.map((id) => contactsOf(env).doc(id)))) {\n if (snapshot.exists) managers.set(snapshot.id, textOf(snapshot.get('email')))\n }\n }\n }\n return docs.map((doc) =>\n pickValues(\n contactTransferValues(doc.id, doc.data, holderOf(env, doc.data), definitions, {\n owner: (uid) => emails.get(uid),\n manager: (id) => managers.get(id),\n }),\n fieldIds,\n ),\n )\n },\n )\n },\n\n async lookup(ctx, requests) {\n const env = await crmTransferEnv(ctx)\n const definitions = await crmCustomDefinitions(env, 'contact')\n const visible = (data: Record<string, unknown>) => visibleIn(env, data['visibleTo'])\n const found = { lookup: new Map<string, string[]>(), docs: new Map<string, Record<string, unknown>>() }\n for (const request of requests) {\n if (request.fieldId === TRANSFER_ID_FIELD) await lookupById(env, contactsOf(env), request, visible, found)\n else if (request.fieldId === 'email') {\n await lookupByField(contactsOf(env), request, 'email', (value) => value.trim().toLowerCase(), visible, found)\n }\n }\n return lookupResult(found, (id, data) => contactTransferValues(id, data, holderOf(env, data), definitions))\n },\n\n async suggest(ctx, request) {\n const env = await crmTransferEnv(ctx)\n const answer: Record<string, ReturnType<typeof rankTransferLookupSuggestions>> = {}\n for (const value of request.values) {\n // People sharing the value's first word: the token the list's own\n // search reads, so a mistyped domain still finds the person.\n const word = value.trim().toLowerCase().split(/[\\s@.+_-]+/)[0]?.slice(0, 12) ?? ''\n if (word.length < 2) {\n answer[value] = []\n continue\n }\n const snapshot = await contactsOf(env).where('searchTokens', 'array-contains', word).limit(IN_LIMIT).get()\n const candidates = snapshot.docs\n .filter((doc) => visibleIn(env, doc.get('visibleTo')))\n .flatMap((doc) => {\n const email = textOf(doc.get('email'))\n return email ? [{ recordId: doc.id, label: email }] : []\n })\n answer[value] = rankTransferLookupSuggestions(value, candidates)\n }\n return answer\n },\n\n async picklists(ctx, ids) {\n const env = await crmTransferEnv(ctx)\n return crmPicklistLists(env, ids, await crmCustomDefinitions(env, 'contact'))\n },\n\n async addPicklistValues(ctx, picklistId, values) {\n await addCrmPicklistValues(await crmTransferEnv(ctx), picklistId, values)\n },\n\n lockedRules: () => [\n {\n fieldId: 'email',\n reason: 'An existing contact’s email is who they are; change it on the contact’s page.',\n forced: { mode: 'keepExisting' },\n },\n {\n fieldId: 'marketingConsent',\n reason:\n 'Consent is never taken from a file: a person gives it on a form, or a team member records how it was given on the contact’s page.',\n refuseValues: true,\n },\n {\n fieldId: 'lifecycleStage',\n reason: 'A stage moves forward only: a later stage in the file advances the contact, an earlier one is held back.',\n forced: { mode: 'overwrite' },\n },\n {\n fieldId: 'doNotCall',\n reason: 'A file can say a person asked not to be called, never that they took it back.',\n forced: { mode: 'overwrite' },\n },\n {\n fieldId: 'name',\n reason: 'The full name is built from the first and last names once either is set.',\n },\n ],\n\n async plan(ctx, input) {\n const env = await crmTransferEnv(ctx)\n requireCrmSuite(env, SUITE_ACT)\n contactImportSite(env)\n const plan = buildTransferPlan(input)\n return holdBackChanges(plan, (row, change) => {\n const before = row.recordId ? input.existing.get(row.recordId) : undefined\n if (change.fieldId === 'lifecycleStage' && before) {\n const from = crmLifecycleStageRank(before['lifecycleStage'])\n const to = crmLifecycleStageRank(change.after)\n if (from >= 0 && (to < from || to < 0)) return 'A stage moves forward only.'\n }\n if (change.fieldId === 'doNotCall' && before?.['doNotCall'] === true && change.after !== true) {\n return 'Do not call is turned off on the contact’s page, never by a file.'\n }\n if (change.fieldId === 'name') {\n const values = Object.fromEntries(row.diff.map((entry) => [entry.fieldId, entry.after]))\n const first = 'firstName' in values ? values['firstName'] : before?.['firstName']\n const last = 'lastName' in values ? values['lastName'] : before?.['lastName']\n if (textOf(first) || textOf(last)) return 'Built from the first and last names.'\n }\n return null\n })\n },\n\n async apply(ctx, chunk, writer) {\n const env = await crmTransferEnv(ctx)\n requireCrmSuite(env, SUITE_ACT)\n const { hostId, group } = contactImportSite(env)\n const run: ApplyRun = {\n env,\n hostId,\n group,\n actorUid: ctx.actorUid,\n definitions: await crmCustomDefinitions(env, 'contact'),\n companies: new Map(),\n admit: crmRecordsRoom(env),\n readContact: cachedContactReader(contactsOf(env)),\n }\n const rows = chunk.rows as PlannedTransferRow[]\n const creating: string[] = []\n for (const row of rows) {\n if (row.verdict === 'create' && !(await writer.alreadyApplied(row.index))) {\n const email = textOf(plannedValues(row)['email'])\n if (email) creating.push(email)\n }\n }\n // The capture door's lookups for every new person at once (AGL-3423).\n const batch =\n hostId && creating.length ? await prepareContactCaptureBatch(hostId, creating) : undefined\n const results: TransferRowResult[] = []\n const undo: TransferUndoEntry[] = []\n\n await eachWithinBudget(rows, () => writer.timeLeftMs(), async (row) => {\n const earlier = await writer.alreadyApplied(row.index)\n if (earlier) {\n results.push(earlier)\n return\n }\n const changed = row.diff.map((change) => change.fieldId)\n let result: TransferRowResult\n let entry: TransferUndoEntry | undefined\n try {\n const values = plannedValues(row)\n if (row.verdict === 'update' && row.recordId) {\n const before = (await readContacts(env, [row.recordId], run.definitions)).get(row.recordId)\n if (!before) throw new TransferEngineError('notFound', 404, 'That contact no longer exists.')\n const { skipped } = await writeContact(run, row.recordId, values)\n const after = (await readContacts(env, [row.recordId], run.definitions)).get(row.recordId) ?? {}\n const message = skippedMessage(skipped)\n result = { row: row.index, outcome: 'updated', recordId: row.recordId, ...(message ? { message } : {}) }\n entry = {\n row: row.index,\n recordId: row.recordId,\n action: 'updated',\n previous: pickValues(before, changed),\n written: pickValues(after, changed),\n }\n } else {\n const made = await createContact(run, values, batch)\n const after = (await readContacts(env, [made.contactId], run.definitions)).get(made.contactId) ?? {}\n const message = made.created\n ? skippedMessage(made.skipped)\n : 'Merged into the contact already holding this email.'\n result = {\n row: row.index,\n outcome: made.created ? 'created' : 'updated',\n recordId: made.contactId,\n ...(message ? { message } : {}),\n }\n // A merge into a person somebody else created meanwhile has no\n // \"before\" to put back, so undo leaves it alone.\n entry = made.created\n ? { row: row.index, recordId: made.contactId, action: 'created', written: pickValues(after, changed) }\n : undefined\n }\n } catch (error) {\n result = {\n row: row.index,\n outcome: 'failed',\n ...(row.recordId ? { recordId: row.recordId } : {}),\n message: failureMessage(error),\n }\n entry = undefined\n }\n await writer.markApplied(result, entry)\n results.push(result)\n if (entry) undo.push(entry)\n })\n return { results, undo }\n },\n\n async revert(ctx, snapshot, decisions) {\n const env = await crmTransferEnv(ctx)\n const { hostId, group } = contactImportSite(env)\n const run: ApplyRun = {\n env,\n hostId,\n group,\n actorUid: ctx.actorUid,\n definitions: await crmCustomDefinitions(env, 'contact'),\n companies: new Map(),\n admit: crmRecordsRoom(env),\n readContact: cachedContactReader(contactsOf(env)),\n }\n const current = await readContacts(env, snapshot.entries.map((entry) => entry.recordId), run.definitions)\n const done: TransferUndoStep[] = []\n const conflicts: TransferUndoStep[] = []\n for (const entry of snapshot.entries) {\n const step = planTransferUndo(entry, current.get(entry.recordId) ?? null)\n if (step.action === 'conflict' && decisions?.[entry.recordId] !== 'revert') {\n if (decisions?.[entry.recordId] === 'keep') done.push({ action: 'nothing', recordId: entry.recordId, why: 'alreadyReverted' })\n else conflicts.push(step)\n continue\n }\n if (step.action === 'nothing') {\n done.push(step)\n continue\n }\n if (entry.action === 'created') {\n // The site lets the person go, as \"Remove from this site\" does: a\n // person only this import's site held is deleted, keeping every\n // refusal they made; one another site holds too stays theirs.\n const contactRef = contactsOf(env).doc(entry.recordId)\n let holders: string[] = []\n const removal = await removeContactKeepingRefusals({\n contactRef,\n decide: (contact) => {\n holders = contactFacetHolders(contact)\n return planContactDetach(contact, group)\n },\n nowMs: Date.now(),\n })\n if (removal.outcome === 'deleted') {\n await clearReportsToOf(env.firestore, contactsOf(env), holders, entry.recordId)\n await sweepDealContactRoles(\n env.firestore,\n env.orgRef.collection(CRM_COLLECTIONS.deals),\n entry.recordId,\n null,\n '[crm] transfer undo',\n )\n } else if (removal.outcome === 'detached') {\n await clearReportsToOf(env.firestore, contactsOf(env), [group.groupId], entry.recordId)\n await restampCrmListFieldsOf([contactRef], 'contacts').catch(() => undefined)\n }\n done.push({ action: 'delete', recordId: entry.recordId })\n continue\n }\n const values = step.action === 'restore' || step.action === 'conflict' ? step.values : {}\n await writeContact(run, entry.recordId, values)\n done.push(step)\n }\n return { done, conflicts }\n },\n }\n}\n"],"names":["composeContactName","crmDefaultScopeOf","ORG_CONTACT_HOLDER_ID","contactDisplayName","contactFacetPath","CRM_COLLECTIONS","interactionsForGroup","isContactLifecycleStage","normalizeContactBirthdate","normalizePhone","planContactDetach","readContactFacet","readMarketingBasis","CONTACT_LIFECYCLE_STAGE_LABELS","CONTACT_EXTRA_PHONE_FIELDS","PHONE_FIELDS","buildTransferPlan","planTransferUndo","rankTransferLookupSuggestions","TRANSFER_ID_FIELD","transferLookupNewName","prepareContactCaptureBatch","removeContactKeepingRefusals","restampCrmListFieldsOf","emitHostEvent","FieldValue","contactPrimaryGroup","ORG_HOLDER_GROUP","captureHostContact","CONTACT_NOTES_MAX","cachedContactReader","clearReportsToOf","CONTACT_REPORTS_TO_LOOP_REFUSAL","CONTACT_REPORTS_TO_SELF_REFUSAL","contactFacetHolders","contactReportsToLoops","contactPatch","settleCompanyCounts","sweepDealContactRoles","CONTACT_ALIASES","addCrmPicklistValues","addressFromValues","addressValues","countCrmExport","crmCustomDefinitions","crmMemberEmails","crmMembersTarget","crmPicklistLists","crmRecordsRoom","crmTransferEnv","customTransferValues","customWriteValues","eachWithinBudget","failureMessage","holdBackChanges","IN_LIMIT","isoOf","lookupByField","lookupById","lookupResult","pickValues","plannedValues","readCrmExportPage","requireCrmSuite","requireSite","textOf","TransferEngineError","visibleIn","companyForName","addContactByHand","CONTACT_TRANSFER_DERIVED","CONTACT_TRANSFER_FIELDS","CONTACT_TRANSFER_GROUPS","CRM_MEMBERS_TARGET","CRM_TIMESTAMP_FIELDS","crmCustomTransferFields","crmLifecycleStageOf","crmLifecycleStageRank","CONTACT_TRANSFER_INTERACTION_SUMMARY","SUITE_ACT","contactsOf","env","orgRef","collection","holderOf","contact","group","org","CAPTURE_REFUSALS","band","erased","error","contactTransferValues","id","definitions","names","facet","groupId","text","value","stage","lifecycleStage","basis","ownerUid","managerId","reportsToContactId","name","email","salutation","firstName","lastName","birthdate","phone","mobilePhone","homePhone","otherPhone","fax","doNotCall","assistantName","assistantPhone","jobTitle","department","company","companyName","companyId","reportsTo","manager","address","otherAddress","owner","leadSource","tags","Array","isArray","notes","marketingConsent","sources","Object","keys","lastInteractionAt","interactions","hostIds","atMs","lastEngagedAt","lastEmailEngagementAtMs","createdAt","updatedAt","custom","readContacts","ids","out","Map","at","length","page","slice","filter","includes","snapshot","firestore","getAll","map","doc","data","exists","set","companyLinkFor","run","undefined","create","actorUid","companies","admit","String","get","profileFields","values","stored","fields","skipped","key","max","typed","push","mailing","other","composed","skippedMessage","labels","find","field","label","join","writeContact","contactId","patch","ref","hostId","linkedCompanyName","link","readContact","refused","update","movedFrom","previous","delete","serverTimestamp","counts","previousStage","actor","kind","uid","catch","console","contactImportSite","createContact","batch","fromEntries","staged","verdict","source","interaction","summary","campaignIds","orgId","sourceHostId","extra","created","contactsTransferResource","ctx","standard","derived","system","groups","matchKeys","fieldId","normalizer","aliases","lookupTargets","count","options","scopeTokens","readPage","cursor","fieldIds","emails","docs","managers","Set","lookup","requests","visible","found","request","trim","toLowerCase","suggest","answer","word","split","where","limit","candidates","flatMap","recordId","picklists","addPicklistValues","picklistId","lockedRules","reason","forced","mode","refuseValues","plan","input","row","change","before","existing","from","to","after","diff","entry","first","last","apply","chunk","writer","rows","creating","alreadyApplied","index","results","undo","timeLeftMs","earlier","changed","result","message","outcome","action","written","made","markApplied","revert","decisions","current","entries","done","conflicts","step","why","contactRef","holders","removal","decide","nowMs","Date","now","deals"],"mappings":"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"}
@@ -149,7 +149,6 @@ export const CRM_COMPANIES_RESOURCE = 'crm.companies';
149
149
  label: 'Email',
150
150
  group: 'person',
151
151
  type: 'email',
152
- required: true,
153
152
  matchKey: true,
154
153
  aliases: [
155
154
  'email address',
@@ -159,7 +158,7 @@ export const CRM_COMPANIES_RESOURCE = 'crm.companies';
159
158
  'primary email',
160
159
  'work email'
161
160
  ],
162
- description: 'Who the person is: a contact is found and kept by its email.'
161
+ description: 'Optional. A row with one merges into the contact who has it.'
163
162
  },
164
163
  {
165
164
  id: 'name',