@aglyn/plugins-crm 1.0.0-beta.221 → 1.0.0-beta.223

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 (541) hide show
  1. package/README.md +2 -1
  2. package/package.json +13 -13
  3. package/src/lib/components/activity-list.js +12 -5
  4. package/src/lib/components/activity-list.js.map +1 -1
  5. package/src/lib/components/companies-bulk-bar.d.ts +1 -4
  6. package/src/lib/components/companies-bulk-bar.js +7 -20
  7. package/src/lib/components/companies-bulk-bar.js.map +1 -1
  8. package/src/lib/components/companies-section.d.ts +3 -3
  9. package/src/lib/components/companies-section.js +149 -46
  10. package/src/lib/components/companies-section.js.map +1 -1
  11. package/src/lib/components/company-edit-drawer.js +281 -20
  12. package/src/lib/components/company-edit-drawer.js.map +1 -1
  13. package/src/lib/components/company-properties-card.js +99 -8
  14. package/src/lib/components/company-properties-card.js.map +1 -1
  15. package/src/lib/components/contact-detail-page.js +3 -1
  16. package/src/lib/components/contact-detail-page.js.map +1 -1
  17. package/src/lib/components/contact-merge-dialog.js +33 -10
  18. package/src/lib/components/contact-merge-dialog.js.map +1 -1
  19. package/src/lib/components/contact-properties-card.d.ts +0 -69
  20. package/src/lib/components/contact-properties-card.js +350 -60
  21. package/src/lib/components/contact-properties-card.js.map +1 -1
  22. package/src/lib/components/contact-reports-to-field.d.ts +46 -0
  23. package/src/lib/components/contact-reports-to-field.js +67 -0
  24. package/src/lib/components/contact-reports-to-field.js.map +1 -0
  25. package/src/lib/components/contacts-bulk-bar.d.ts +1 -8
  26. package/src/lib/components/contacts-bulk-bar.js +7 -19
  27. package/src/lib/components/contacts-bulk-bar.js.map +1 -1
  28. package/src/lib/components/contacts-section.js +46 -33
  29. package/src/lib/components/contacts-section.js.map +1 -1
  30. package/src/lib/components/crm-call-actions.d.ts +10 -0
  31. package/src/lib/components/crm-call-actions.js +26 -9
  32. package/src/lib/components/crm-call-actions.js.map +1 -1
  33. package/src/lib/components/crm-next-activity-column.js +1 -1
  34. package/src/lib/components/crm-next-activity-column.js.map +1 -1
  35. package/src/lib/components/crm-record-picker.d.ts +15 -0
  36. package/src/lib/components/crm-record-picker.js +16 -10
  37. package/src/lib/components/crm-record-picker.js.map +1 -1
  38. package/src/lib/components/crm-transfer-buttons.d.ts +54 -0
  39. package/src/lib/components/crm-transfer-buttons.js +167 -0
  40. package/src/lib/components/crm-transfer-buttons.js.map +1 -0
  41. package/src/lib/components/deal-contact-roles-card.d.ts +46 -0
  42. package/src/lib/components/deal-contact-roles-card.js +368 -0
  43. package/src/lib/components/deal-contact-roles-card.js.map +1 -0
  44. package/src/lib/components/deal-detail-page.d.ts +3 -2
  45. package/src/lib/components/deal-detail-page.js +25 -6
  46. package/src/lib/components/deal-detail-page.js.map +1 -1
  47. package/src/lib/components/deal-edit-drawer.d.ts +10 -0
  48. package/src/lib/components/deal-edit-drawer.js +219 -10
  49. package/src/lib/components/deal-edit-drawer.js.map +1 -1
  50. package/src/lib/components/deal-properties-card.d.ts +7 -0
  51. package/src/lib/components/deal-properties-card.js +34 -3
  52. package/src/lib/components/deal-properties-card.js.map +1 -1
  53. package/src/lib/components/deal-stage-card.d.ts +4 -0
  54. package/src/lib/components/deal-stage-card.js +10 -2
  55. package/src/lib/components/deal-stage-card.js.map +1 -1
  56. package/src/lib/components/deals-bulk-bar.d.ts +0 -3
  57. package/src/lib/components/deals-bulk-bar.js +7 -20
  58. package/src/lib/components/deals-bulk-bar.js.map +1 -1
  59. package/src/lib/components/deals-section.d.ts +3 -3
  60. package/src/lib/components/deals-section.js +123 -63
  61. package/src/lib/components/deals-section.js.map +1 -1
  62. package/src/lib/components/fields-section.js +31 -17
  63. package/src/lib/components/fields-section.js.map +1 -1
  64. package/src/lib/components/lead-convert-dialog.d.ts +4 -0
  65. package/src/lib/components/lead-convert-dialog.js +23 -1
  66. package/src/lib/components/lead-convert-dialog.js.map +1 -1
  67. package/src/lib/components/lead-detail-page.js +8 -2
  68. package/src/lib/components/lead-detail-page.js.map +1 -1
  69. package/src/lib/components/lead-profile-fields.d.ts +71 -0
  70. package/src/lib/components/lead-profile-fields.js +386 -0
  71. package/src/lib/components/lead-profile-fields.js.map +1 -0
  72. package/src/lib/components/lead-properties-card.d.ts +2 -1
  73. package/src/lib/components/lead-properties-card.js +85 -176
  74. package/src/lib/components/lead-properties-card.js.map +1 -1
  75. package/src/lib/components/lead-source-select.d.ts +4 -23
  76. package/src/lib/components/lead-source-select.js +9 -73
  77. package/src/lib/components/lead-source-select.js.map +1 -1
  78. package/src/lib/components/lead-status-chip.d.ts +9 -3
  79. package/src/lib/components/lead-status-chip.js +8 -4
  80. package/src/lib/components/lead-status-chip.js.map +1 -1
  81. package/src/lib/components/lead-status-options.d.ts +20 -0
  82. package/src/lib/components/lead-status-options.js +51 -0
  83. package/src/lib/components/lead-status-options.js.map +1 -0
  84. package/src/lib/components/lead-unqualify-dialog.d.ts +5 -0
  85. package/src/lib/components/lead-unqualify-dialog.js +50 -18
  86. package/src/lib/components/lead-unqualify-dialog.js.map +1 -1
  87. package/src/lib/components/leads-bulk-bar.d.ts +0 -3
  88. package/src/lib/components/leads-bulk-bar.js +29 -29
  89. package/src/lib/components/leads-bulk-bar.js.map +1 -1
  90. package/src/lib/components/leads-section.js +120 -68
  91. package/src/lib/components/leads-section.js.map +1 -1
  92. package/src/lib/components/linked-deals-card.d.ts +4 -0
  93. package/src/lib/components/linked-deals-card.js +47 -3
  94. package/src/lib/components/linked-deals-card.js.map +1 -1
  95. package/src/lib/components/log-activity-dialog.js +43 -3
  96. package/src/lib/components/log-activity-dialog.js.map +1 -1
  97. package/src/lib/components/new-contact-drawer.d.ts +8 -0
  98. package/src/lib/components/new-contact-drawer.js +108 -6
  99. package/src/lib/components/new-contact-drawer.js.map +1 -1
  100. package/src/lib/components/new-lead-drawer.d.ts +9 -2
  101. package/src/lib/components/new-lead-drawer.js +88 -121
  102. package/src/lib/components/new-lead-drawer.js.map +1 -1
  103. package/src/lib/components/picklist-select.d.ts +36 -0
  104. package/src/lib/components/picklist-select.js +114 -0
  105. package/src/lib/components/picklist-select.js.map +1 -0
  106. package/src/lib/components/picklist-values-card.d.ts +34 -0
  107. package/src/lib/components/{lead-source-values-card.js → picklist-values-card.js} +241 -58
  108. package/src/lib/components/picklist-values-card.js.map +1 -0
  109. package/src/lib/components/pipeline-stages-dialog.d.ts +7 -0
  110. package/src/lib/components/pipeline-stages-dialog.js +26 -4
  111. package/src/lib/components/pipeline-stages-dialog.js.map +1 -1
  112. package/src/lib/components/pipelines-dialog.js +15 -6
  113. package/src/lib/components/pipelines-dialog.js.map +1 -1
  114. package/src/lib/components/recent-activity-feed.js +20 -5
  115. package/src/lib/components/recent-activity-feed.js.map +1 -1
  116. package/src/lib/components/recipes-card.js +4 -2
  117. package/src/lib/components/recipes-card.js.map +1 -1
  118. package/src/lib/components/record-tasks-card.js +15 -8
  119. package/src/lib/components/record-tasks-card.js.map +1 -1
  120. package/src/lib/components/reports/forecast-card.d.ts +6 -0
  121. package/src/lib/components/reports/forecast-card.js +101 -3
  122. package/src/lib/components/reports/forecast-card.js.map +1 -1
  123. package/src/lib/components/reports/lead-funnel-card.d.ts +12 -0
  124. package/src/lib/components/reports/lead-funnel-card.js +9 -5
  125. package/src/lib/components/reports/lead-funnel-card.js.map +1 -1
  126. package/src/lib/components/reports/lead-source-card.d.ts +23 -0
  127. package/src/lib/components/reports/lead-source-card.js +318 -0
  128. package/src/lib/components/reports/lead-source-card.js.map +1 -0
  129. package/src/lib/components/reports/pipeline-card.js +2 -1
  130. package/src/lib/components/reports/pipeline-card.js.map +1 -1
  131. package/src/lib/components/reports/report-export.js +1 -1
  132. package/src/lib/components/reports/report-export.js.map +1 -1
  133. package/src/lib/components/reports-section.js +8 -0
  134. package/src/lib/components/reports-section.js.map +1 -1
  135. package/src/lib/components/sharing-rule-drawer.d.ts +5 -0
  136. package/src/lib/components/sharing-rule-drawer.js +108 -19
  137. package/src/lib/components/sharing-rule-drawer.js.map +1 -1
  138. package/src/lib/components/sharing-rules-card.js +11 -3
  139. package/src/lib/components/sharing-rules-card.js.map +1 -1
  140. package/src/lib/components/task-cells.d.ts +9 -1
  141. package/src/lib/components/task-cells.js +9 -4
  142. package/src/lib/components/task-cells.js.map +1 -1
  143. package/src/lib/components/task-edit-drawer.js +111 -43
  144. package/src/lib/components/task-edit-drawer.js.map +1 -1
  145. package/src/lib/components/tasks-bulk-bar.d.ts +0 -3
  146. package/src/lib/components/tasks-bulk-bar.js +7 -20
  147. package/src/lib/components/tasks-bulk-bar.js.map +1 -1
  148. package/src/lib/components/tasks-calendar.d.ts +3 -0
  149. package/src/lib/components/tasks-calendar.js +8 -1
  150. package/src/lib/components/tasks-calendar.js.map +1 -1
  151. package/src/lib/components/tasks-section.d.ts +3 -3
  152. package/src/lib/components/tasks-section.js +58 -43
  153. package/src/lib/components/tasks-section.js.map +1 -1
  154. package/src/lib/constants/api-routes.d.ts +2 -9
  155. package/src/lib/constants/api-routes.js +1 -7
  156. package/src/lib/constants/api-routes.js.map +1 -1
  157. package/src/lib/constants/bundle-common.d.ts +6 -0
  158. package/src/lib/constants/bundle-common.js +11 -0
  159. package/src/lib/constants/bundle-common.js.map +1 -1
  160. package/src/lib/constants/company-filters.d.ts +14 -0
  161. package/src/lib/constants/company-filters.js +51 -1
  162. package/src/lib/constants/company-filters.js.map +1 -1
  163. package/src/lib/constants/contact-filters.d.ts +2 -0
  164. package/src/lib/constants/contact-filters.js +18 -1
  165. package/src/lib/constants/contact-filters.js.map +1 -1
  166. package/src/lib/constants/deal-filters.d.ts +22 -1
  167. package/src/lib/constants/deal-filters.js +67 -4
  168. package/src/lib/constants/deal-filters.js.map +1 -1
  169. package/src/lib/declarations.console-server.d.ts +3 -0
  170. package/src/lib/declarations.console-server.js +35 -0
  171. package/src/lib/declarations.console-server.js.map +1 -1
  172. package/src/lib/declarations.d.ts +26 -0
  173. package/src/lib/declarations.js +35 -0
  174. package/src/lib/declarations.js.map +1 -0
  175. package/src/lib/declarations.server.d.ts +11 -0
  176. package/src/lib/declarations.server.js +97 -1
  177. package/src/lib/declarations.server.js.map +1 -1
  178. package/src/lib/hooks/use-company-picklists.d.ts +15 -0
  179. package/src/lib/hooks/use-company-picklists.js +55 -0
  180. package/src/lib/hooks/use-company-picklists.js.map +1 -0
  181. package/src/lib/hooks/use-crm-picklist.d.ts +25 -0
  182. package/src/lib/hooks/use-crm-picklist.js +53 -0
  183. package/src/lib/hooks/use-crm-picklist.js.map +1 -0
  184. package/src/lib/hooks/use-crm-record-names.d.ts +16 -0
  185. package/src/lib/hooks/use-crm-record-names.js +45 -19
  186. package/src/lib/hooks/use-crm-record-names.js.map +1 -1
  187. package/src/lib/hooks/use-crm-task-picklists.d.ts +11 -0
  188. package/src/lib/hooks/use-crm-task-picklists.js +45 -0
  189. package/src/lib/hooks/use-crm-task-picklists.js.map +1 -0
  190. package/src/lib/hooks/use-deals.d.ts +14 -0
  191. package/src/lib/hooks/use-deals.js +29 -0
  192. package/src/lib/hooks/use-deals.js.map +1 -1
  193. package/src/lib/hooks/use-lead-picklists.d.ts +14 -0
  194. package/src/lib/hooks/use-lead-picklists.js +46 -0
  195. package/src/lib/hooks/use-lead-picklists.js.map +1 -0
  196. package/src/lib/hooks/use-lead-source-picklist.d.ts +5 -19
  197. package/src/lib/hooks/use-lead-source-picklist.js +12 -22
  198. package/src/lib/hooks/use-lead-source-picklist.js.map +1 -1
  199. package/src/lib/hooks/use-lead-status-picklist.d.ts +9 -0
  200. package/src/lib/hooks/use-lead-status-picklist.js +40 -0
  201. package/src/lib/hooks/use-lead-status-picklist.js.map +1 -0
  202. package/src/lib/model/companies.d.ts +32 -3
  203. package/src/lib/model/companies.js +133 -16
  204. package/src/lib/model/companies.js.map +1 -1
  205. package/src/lib/model/contact-merge.d.ts +27 -3
  206. package/src/lib/model/contact-merge.js +81 -7
  207. package/src/lib/model/contact-merge.js.map +1 -1
  208. package/src/lib/model/contact-record.d.ts +17 -0
  209. package/src/lib/model/contact-record.js +17 -2
  210. package/src/lib/model/contact-record.js.map +1 -1
  211. package/src/lib/model/contact-update.d.ts +31 -2
  212. package/src/lib/model/contact-update.js +14 -0
  213. package/src/lib/model/contact-update.js.map +1 -1
  214. package/src/lib/model/crm-list-query.d.ts +5 -0
  215. package/src/lib/model/crm-list-query.js +8 -0
  216. package/src/lib/model/crm-list-query.js.map +1 -1
  217. package/src/lib/model/crm-next-activity.d.ts +107 -0
  218. package/src/lib/model/crm-next-activity.js +140 -0
  219. package/src/lib/model/crm-next-activity.js.map +1 -0
  220. package/src/lib/model/crm-recipes.d.ts +40 -0
  221. package/src/lib/model/crm-recipes.js +259 -0
  222. package/src/lib/model/crm-recipes.js.map +1 -0
  223. package/src/lib/model/crm-record-counts.d.ts +36 -0
  224. package/src/lib/model/crm-record-counts.js +54 -0
  225. package/src/lib/model/crm-record-counts.js.map +1 -0
  226. package/src/lib/model/crm-record-lists.d.ts +23 -0
  227. package/src/lib/model/crm-record-lists.js +161 -0
  228. package/src/lib/model/crm-record-lists.js.map +1 -0
  229. package/src/lib/model/crm-reports.d.ts +73 -3
  230. package/src/lib/model/crm-reports.js +120 -1
  231. package/src/lib/model/crm-reports.js.map +1 -1
  232. package/src/lib/model/crm-sharing.d.ts +21 -3
  233. package/src/lib/model/crm-sharing.js +27 -6
  234. package/src/lib/model/crm-sharing.js.map +1 -1
  235. package/src/lib/model/crm-task-reminders.d.ts +152 -0
  236. package/src/lib/model/crm-task-reminders.js +161 -0
  237. package/src/lib/model/crm-task-reminders.js.map +1 -0
  238. package/src/lib/model/deal-board-model.d.ts +8 -2
  239. package/src/lib/model/deal-board-model.js +15 -2
  240. package/src/lib/model/deal-board-model.js.map +1 -1
  241. package/src/lib/model/deal-contact-roles.d.ts +45 -0
  242. package/src/lib/model/deal-contact-roles.js +73 -0
  243. package/src/lib/model/deal-contact-roles.js.map +1 -0
  244. package/src/lib/model/deal-form-model.d.ts +56 -0
  245. package/src/lib/model/deal-form-model.js +79 -7
  246. package/src/lib/model/deal-form-model.js.map +1 -1
  247. package/src/lib/model/download-text-file.d.ts +23 -0
  248. package/src/lib/model/download-text-file.js +34 -0
  249. package/src/lib/model/download-text-file.js.map +1 -0
  250. package/src/lib/model/lead-filters.d.ts +36 -2
  251. package/src/lib/model/lead-filters.js +123 -2
  252. package/src/lib/model/lead-filters.js.map +1 -1
  253. package/src/lib/model/lead-source-direction.d.ts +38 -0
  254. package/src/lib/model/lead-source-direction.js +52 -0
  255. package/src/lib/model/lead-source-direction.js.map +1 -0
  256. package/src/lib/model/next-activity.d.ts +1 -1
  257. package/src/lib/model/next-activity.js.map +1 -1
  258. package/src/lib/model/picklist-values.d.ts +119 -0
  259. package/src/lib/model/picklist-values.js +256 -0
  260. package/src/lib/model/picklist-values.js.map +1 -0
  261. package/src/lib/model/record-facts-disclosed.d.ts +81 -0
  262. package/src/lib/model/record-facts-disclosed.js +281 -0
  263. package/src/lib/model/record-facts-disclosed.js.map +1 -0
  264. package/src/lib/model/record-facts.d.ts +215 -34
  265. package/src/lib/model/record-facts.js +307 -128
  266. package/src/lib/model/record-facts.js.map +1 -1
  267. package/src/lib/model/task-picklists.d.ts +52 -0
  268. package/src/lib/model/task-picklists.js +83 -0
  269. package/src/lib/model/task-picklists.js.map +1 -0
  270. package/src/lib/model/task-routes.d.ts +13 -0
  271. package/src/lib/model/task-routes.js +23 -4
  272. package/src/lib/model/task-routes.js.map +1 -1
  273. package/src/lib/plan-entitlements.js +6 -4
  274. package/src/lib/plan-entitlements.js.map +1 -1
  275. package/src/lib/plugin.js +17 -0
  276. package/src/lib/plugin.js.map +1 -1
  277. package/src/lib/server/api-v1/contacts.js +220 -14
  278. package/src/lib/server/api-v1/contacts.js.map +1 -1
  279. package/src/lib/server/api-v1/crm-activities.js +14 -1
  280. package/src/lib/server/api-v1/crm-activities.js.map +1 -1
  281. package/src/lib/server/api-v1/crm-companies.js +123 -14
  282. package/src/lib/server/api-v1/crm-companies.js.map +1 -1
  283. package/src/lib/server/api-v1/crm-deals.js +291 -26
  284. package/src/lib/server/api-v1/crm-deals.js.map +1 -1
  285. package/src/lib/server/api-v1/crm-leads.js +144 -38
  286. package/src/lib/server/api-v1/crm-leads.js.map +1 -1
  287. package/src/lib/server/api-v1/crm-pipelines.d.ts +6 -0
  288. package/src/lib/server/api-v1/crm-pipelines.js +8 -2
  289. package/src/lib/server/api-v1/crm-pipelines.js.map +1 -1
  290. package/src/lib/server/api-v1/crm-tasks.js +78 -34
  291. package/src/lib/server/api-v1/crm-tasks.js.map +1 -1
  292. package/src/lib/server/api-v1/openapi.d.ts +0 -11
  293. package/src/lib/server/api-v1/openapi.js +171 -16
  294. package/src/lib/server/api-v1/openapi.js.map +1 -1
  295. package/src/lib/server/assign-contact-owner.d.ts +188 -0
  296. package/src/lib/server/assign-contact-owner.js +446 -0
  297. package/src/lib/server/assign-contact-owner.js.map +1 -0
  298. package/src/lib/server/associate-company-by-domain.d.ts +70 -0
  299. package/src/lib/server/associate-company-by-domain.js +153 -0
  300. package/src/lib/server/associate-company-by-domain.js.map +1 -0
  301. package/src/lib/server/automation-steps.d.ts +140 -0
  302. package/src/lib/server/automation-steps.js +669 -0
  303. package/src/lib/server/automation-steps.js.map +1 -0
  304. package/src/lib/server/capture-contact.d.ts +17 -0
  305. package/src/lib/server/capture-contact.js +95 -26
  306. package/src/lib/server/capture-contact.js.map +1 -1
  307. package/src/lib/server/capture-host-contact.d.ts +104 -0
  308. package/src/lib/server/capture-host-contact.js +151 -0
  309. package/src/lib/server/capture-host-contact.js.map +1 -0
  310. package/src/lib/server/company-children.d.ts +25 -0
  311. package/src/lib/server/company-children.js +42 -0
  312. package/src/lib/server/company-children.js.map +1 -0
  313. package/src/lib/server/company-delete.d.ts +18 -0
  314. package/src/lib/server/company-delete.js +44 -21
  315. package/src/lib/server/company-delete.js.map +1 -1
  316. package/src/lib/server/contact-email-history.js +21 -19
  317. package/src/lib/server/contact-email-history.js.map +1 -1
  318. package/src/lib/server/contact-remove.js +27 -2
  319. package/src/lib/server/contact-remove.js.map +1 -1
  320. package/src/lib/server/contact-reports-to.d.ts +61 -0
  321. package/src/lib/server/contact-reports-to.js +114 -0
  322. package/src/lib/server/contact-reports-to.js.map +1 -0
  323. package/src/lib/server/contact-update.d.ts +42 -1
  324. package/src/lib/server/contact-update.js +204 -23
  325. package/src/lib/server/contact-update.js.map +1 -1
  326. package/src/lib/server/convert-host-lead.d.ts +46 -1
  327. package/src/lib/server/convert-host-lead.js +173 -15
  328. package/src/lib/server/convert-host-lead.js.map +1 -1
  329. package/src/lib/server/convert-open-lead.js +12 -5
  330. package/src/lib/server/convert-open-lead.js.map +1 -1
  331. package/src/lib/server/crm-email-activity.d.ts +118 -0
  332. package/src/lib/server/crm-email-activity.js +148 -0
  333. package/src/lib/server/crm-email-activity.js.map +1 -0
  334. package/src/lib/server/crm-inbound-email.js +1 -1
  335. package/src/lib/server/crm-inbound-email.js.map +1 -1
  336. package/src/lib/server/crm-next-activity.d.ts +74 -0
  337. package/src/lib/server/crm-next-activity.js +194 -0
  338. package/src/lib/server/crm-next-activity.js.map +1 -0
  339. package/src/lib/server/crm-record-indexes.d.ts +45 -0
  340. package/src/lib/server/crm-record-indexes.js +78 -0
  341. package/src/lib/server/crm-record-indexes.js.map +1 -0
  342. package/src/lib/server/crm-sharing.d.ts +9 -1
  343. package/src/lib/server/crm-sharing.js +23 -3
  344. package/src/lib/server/crm-sharing.js.map +1 -1
  345. package/src/lib/server/deal-contact-roles.d.ts +27 -0
  346. package/src/lib/server/deal-contact-roles.js +89 -0
  347. package/src/lib/server/deal-contact-roles.js.map +1 -0
  348. package/src/lib/server/email-send.js +2 -1
  349. package/src/lib/server/email-send.js.map +1 -1
  350. package/src/lib/server/lead-convert.d.ts +5 -0
  351. package/src/lib/server/lead-convert.js +19 -3
  352. package/src/lib/server/lead-convert.js.map +1 -1
  353. package/src/lib/server/lead-create.d.ts +17 -2
  354. package/src/lib/server/lead-create.js +46 -14
  355. package/src/lib/server/lead-create.js.map +1 -1
  356. package/src/lib/server/lead-nurturing.d.ts +6 -0
  357. package/src/lib/server/lead-nurturing.js +57 -20
  358. package/src/lib/server/lead-nurturing.js.map +1 -1
  359. package/src/lib/server/lead-picklists.d.ts +35 -0
  360. package/src/lib/server/lead-picklists.js +52 -0
  361. package/src/lib/server/lead-picklists.js.map +1 -0
  362. package/src/lib/server/lead-source-picklist.d.ts +1 -13
  363. package/src/lib/server/lead-source-picklist.js +6 -33
  364. package/src/lib/server/lead-source-picklist.js.map +1 -1
  365. package/src/lib/server/merge-contacts.js +23 -5
  366. package/src/lib/server/merge-contacts.js.map +1 -1
  367. package/src/lib/server/next-activity-routes.js +2 -1
  368. package/src/lib/server/next-activity-routes.js.map +1 -1
  369. package/src/lib/server/person-eraser.d.ts +53 -0
  370. package/src/lib/server/person-eraser.js +149 -0
  371. package/src/lib/server/person-eraser.js.map +1 -0
  372. package/src/lib/server/person-records.d.ts +69 -0
  373. package/src/lib/server/person-records.js +317 -0
  374. package/src/lib/server/person-records.js.map +1 -0
  375. package/src/lib/server/person-refund.d.ts +97 -0
  376. package/src/lib/server/person-refund.js +221 -0
  377. package/src/lib/server/person-refund.js.map +1 -0
  378. package/src/lib/server/picklist-values.d.ts +21 -0
  379. package/src/lib/server/picklist-values.js +308 -0
  380. package/src/lib/server/picklist-values.js.map +1 -0
  381. package/src/lib/server/read-picklist.d.ts +44 -0
  382. package/src/lib/server/read-picklist.js +65 -0
  383. package/src/lib/server/read-picklist.js.map +1 -0
  384. package/src/lib/server/recipe-routes.js +22 -8
  385. package/src/lib/server/recipe-routes.js.map +1 -1
  386. package/src/lib/server/record-email-state.js +7 -1
  387. package/src/lib/server/record-email-state.js.map +1 -1
  388. package/src/lib/server/record-facts.d.ts +3 -0
  389. package/src/lib/server/record-facts.js +233 -31
  390. package/src/lib/server/record-facts.js.map +1 -1
  391. package/src/lib/server/record-origin.d.ts +27 -0
  392. package/src/lib/server/record-origin.js +104 -0
  393. package/src/lib/server/record-origin.js.map +1 -0
  394. package/src/lib/server/record-timeline.js +40 -3
  395. package/src/lib/server/record-timeline.js.map +1 -1
  396. package/src/lib/server/suite-gate.js +4 -3
  397. package/src/lib/server/suite-gate.js.map +1 -1
  398. package/src/lib/server/task-reminders-route.js +2 -1
  399. package/src/lib/server/task-reminders-route.js.map +1 -1
  400. package/src/lib/server/task-routes.js +33 -17
  401. package/src/lib/server/task-routes.js.map +1 -1
  402. package/src/lib/server-deal-stage.d.ts +5 -1
  403. package/src/lib/server-deal-stage.js +10 -5
  404. package/src/lib/server-deal-stage.js.map +1 -1
  405. package/src/lib/server.d.ts +8 -3
  406. package/src/lib/server.js +47 -43
  407. package/src/lib/server.js.map +1 -1
  408. package/src/lib/testing/memory-firestore.d.ts +55 -0
  409. package/src/lib/testing/memory-firestore.js +335 -0
  410. package/src/lib/testing/memory-firestore.js.map +1 -0
  411. package/src/lib/testing/stand-in-email-send-index.d.ts +25 -0
  412. package/src/lib/testing/stand-in-email-send-index.js +49 -0
  413. package/src/lib/testing/stand-in-email-send-index.js.map +1 -0
  414. package/src/lib/transfer/activities.d.ts +30 -0
  415. package/src/lib/transfer/activities.js +132 -0
  416. package/src/lib/transfer/activities.js.map +1 -0
  417. package/src/lib/transfer/aliases.d.ts +22 -0
  418. package/src/lib/transfer/aliases.js +1342 -0
  419. package/src/lib/transfer/aliases.js.map +1 -0
  420. package/src/lib/transfer/common.d.ts +222 -0
  421. package/src/lib/transfer/common.js +832 -0
  422. package/src/lib/transfer/common.js.map +1 -0
  423. package/src/lib/transfer/companies.d.ts +43 -0
  424. package/src/lib/transfer/companies.js +549 -0
  425. package/src/lib/transfer/companies.js.map +1 -0
  426. package/src/lib/transfer/contacts.d.ts +31 -0
  427. package/src/lib/transfer/contacts.js +727 -0
  428. package/src/lib/transfer/contacts.js.map +1 -0
  429. package/src/lib/transfer/deals.d.ts +66 -0
  430. package/src/lib/transfer/deals.js +698 -0
  431. package/src/lib/transfer/deals.js.map +1 -0
  432. package/src/lib/transfer/email-templates-package.d.ts +40 -0
  433. package/src/lib/transfer/email-templates-package.js +76 -0
  434. package/src/lib/transfer/email-templates-package.js.map +1 -0
  435. package/src/lib/transfer/email-templates-package.server.d.ts +32 -0
  436. package/src/lib/transfer/email-templates-package.server.js +176 -0
  437. package/src/lib/transfer/email-templates-package.server.js.map +1 -0
  438. package/src/lib/transfer/fields.d.ts +102 -0
  439. package/src/lib/transfer/fields.js +1755 -0
  440. package/src/lib/transfer/fields.js.map +1 -0
  441. package/src/lib/transfer/leads.d.ts +30 -0
  442. package/src/lib/transfer/leads.js +582 -0
  443. package/src/lib/transfer/leads.js.map +1 -0
  444. package/src/lib/transfer/pipelines.d.ts +21 -0
  445. package/src/lib/transfer/pipelines.js +172 -0
  446. package/src/lib/transfer/pipelines.js.map +1 -0
  447. package/src/lib/transfer/register.d.ts +47 -0
  448. package/src/lib/transfer/register.js +277 -0
  449. package/src/lib/transfer/register.js.map +1 -0
  450. package/src/lib/transfer/tasks.d.ts +30 -0
  451. package/src/lib/transfer/tasks.js +418 -0
  452. package/src/lib/transfer/tasks.js.map +1 -0
  453. package/src/lib/transfer/ui.d.ts +20 -0
  454. package/src/lib/transfer/ui.js +42 -0
  455. package/src/lib/transfer/ui.js.map +1 -0
  456. package/src/lib/components/company-import-drawer.d.ts +0 -42
  457. package/src/lib/components/company-import-drawer.js +0 -99
  458. package/src/lib/components/company-import-drawer.js.map +0 -1
  459. package/src/lib/components/contact-import-drawer.d.ts +0 -46
  460. package/src/lib/components/contact-import-drawer.js +0 -149
  461. package/src/lib/components/contact-import-drawer.js.map +0 -1
  462. package/src/lib/components/crm-export-all-button.d.ts +0 -39
  463. package/src/lib/components/crm-export-all-button.js +0 -98
  464. package/src/lib/components/crm-export-all-button.js.map +0 -1
  465. package/src/lib/components/csv-import-drawer.d.ts +0 -139
  466. package/src/lib/components/csv-import-drawer.js +0 -757
  467. package/src/lib/components/csv-import-drawer.js.map +0 -1
  468. package/src/lib/components/deal-import-drawer.d.ts +0 -24
  469. package/src/lib/components/deal-import-drawer.js +0 -83
  470. package/src/lib/components/deal-import-drawer.js.map +0 -1
  471. package/src/lib/components/lead-import-drawer.d.ts +0 -27
  472. package/src/lib/components/lead-import-drawer.js +0 -118
  473. package/src/lib/components/lead-import-drawer.js.map +0 -1
  474. package/src/lib/components/lead-source-values-card.d.ts +0 -27
  475. package/src/lib/components/lead-source-values-card.js.map +0 -1
  476. package/src/lib/components/task-import-drawer.d.ts +0 -24
  477. package/src/lib/components/task-import-drawer.js +0 -82
  478. package/src/lib/components/task-import-drawer.js.map +0 -1
  479. package/src/lib/model/companies-csv.d.ts +0 -36
  480. package/src/lib/model/companies-csv.js +0 -38
  481. package/src/lib/model/companies-csv.js.map +0 -1
  482. package/src/lib/model/contacts-csv.d.ts +0 -54
  483. package/src/lib/model/contacts-csv.js +0 -67
  484. package/src/lib/model/contacts-csv.js.map +0 -1
  485. package/src/lib/model/crm-company-import.d.ts +0 -154
  486. package/src/lib/model/crm-company-import.js +0 -331
  487. package/src/lib/model/crm-company-import.js.map +0 -1
  488. package/src/lib/model/crm-csv.d.ts +0 -239
  489. package/src/lib/model/crm-csv.js +0 -467
  490. package/src/lib/model/crm-csv.js.map +0 -1
  491. package/src/lib/model/crm-deal-import.d.ts +0 -112
  492. package/src/lib/model/crm-deal-import.js +0 -263
  493. package/src/lib/model/crm-deal-import.js.map +0 -1
  494. package/src/lib/model/crm-import.d.ts +0 -250
  495. package/src/lib/model/crm-import.js +0 -467
  496. package/src/lib/model/crm-import.js.map +0 -1
  497. package/src/lib/model/crm-lead-import.d.ts +0 -138
  498. package/src/lib/model/crm-lead-import.js +0 -446
  499. package/src/lib/model/crm-lead-import.js.map +0 -1
  500. package/src/lib/model/crm-task-import.d.ts +0 -94
  501. package/src/lib/model/crm-task-import.js +0 -275
  502. package/src/lib/model/crm-task-import.js.map +0 -1
  503. package/src/lib/model/deals-csv.d.ts +0 -32
  504. package/src/lib/model/deals-csv.js +0 -36
  505. package/src/lib/model/deals-csv.js.map +0 -1
  506. package/src/lib/model/import-column-shapes.d.ts +0 -36
  507. package/src/lib/model/import-column-shapes.js +0 -76
  508. package/src/lib/model/import-column-shapes.js.map +0 -1
  509. package/src/lib/model/lead-source-values.d.ts +0 -82
  510. package/src/lib/model/lead-source-values.js +0 -149
  511. package/src/lib/model/lead-source-values.js.map +0 -1
  512. package/src/lib/model/leads-csv.d.ts +0 -40
  513. package/src/lib/model/leads-csv.js +0 -40
  514. package/src/lib/model/leads-csv.js.map +0 -1
  515. package/src/lib/model/tasks-csv.d.ts +0 -28
  516. package/src/lib/model/tasks-csv.js +0 -28
  517. package/src/lib/model/tasks-csv.js.map +0 -1
  518. package/src/lib/server/companies-import.d.ts +0 -57
  519. package/src/lib/server/companies-import.js +0 -242
  520. package/src/lib/server/companies-import.js.map +0 -1
  521. package/src/lib/server/contacts-import.d.ts +0 -109
  522. package/src/lib/server/contacts-import.js +0 -393
  523. package/src/lib/server/contacts-import.js.map +0 -1
  524. package/src/lib/server/deals-import.d.ts +0 -76
  525. package/src/lib/server/deals-import.js +0 -248
  526. package/src/lib/server/deals-import.js.map +0 -1
  527. package/src/lib/server/export-route.d.ts +0 -60
  528. package/src/lib/server/export-route.js +0 -447
  529. package/src/lib/server/export-route.js.map +0 -1
  530. package/src/lib/server/import-context.d.ts +0 -87
  531. package/src/lib/server/import-context.js +0 -182
  532. package/src/lib/server/import-context.js.map +0 -1
  533. package/src/lib/server/lead-source-values.d.ts +0 -50
  534. package/src/lib/server/lead-source-values.js +0 -191
  535. package/src/lib/server/lead-source-values.js.map +0 -1
  536. package/src/lib/server/leads-import.d.ts +0 -84
  537. package/src/lib/server/leads-import.js +0 -367
  538. package/src/lib/server/leads-import.js.map +0 -1
  539. package/src/lib/server/tasks-import.d.ts +0 -54
  540. package/src/lib/server/tasks-import.js +0 -160
  541. package/src/lib/server/tasks-import.js.map +0 -1
@@ -25,14 +25,23 @@ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_wi
25
25
  * a domain already held is a `409 company_exists` naming the first — the
26
26
  * contact create's own rule for a second row on one email — and `?domain=`
27
27
  * is the lookup a sync starts with.
28
+ *
29
+ * Salesforce's Account fields (AGL-3514) ride the same object: Type,
30
+ * Industry, Rating, Ownership and Account Source are labels of the org's
31
+ * lists — any other value is a 400 naming what the list allows, and the
32
+ * value a company already holds is kept — the rest are read through
33
+ * `readCrmCompanyAccountFields`, and `parentCompanyId` names another
34
+ * company of the organization that is not this one or below it.
28
35
  */ import { nameSearchFields } from "@aglyn/aglyn/app-utils/name-search";
29
- import { CRM_COLLECTIONS, CRM_MEDIA_IDS_MAX, createResourceUid, crmNewRecordListFields, normalizeAddress, normalizeCompanyDomain, normalizeCrmMediaIds, normalizePhone } from "@aglyn/aglyn/server";
36
+ import { CRM_COLLECTIONS, CRM_COMPANY_ACCOUNT_FIELDS, CRM_COMPANY_PICKLIST_FIELDS, CRM_MEDIA_IDS_MAX, createResourceUid, crmCompanyParentId, crmCompanyParentRefusal, crmNewRecordListFields, judgeCrmCompanyPicklists, normalizeAddress, normalizeCompanyDomain, normalizeCrmMediaIds, normalizePhone, readCrmCompanyAccountFields } from "@aglyn/aglyn/server";
37
+ import { detachChildCompanies } from "../company-children.js";
38
+ import { readCrmPicklist } from "../read-picklist.js";
30
39
  import { apiJson, ApiErrors, restampCrmListFieldsAt } from "@aglyn/tenant-data-admin";
31
40
  import { Timestamp } from "firebase-admin/firestore";
32
41
  import { claimWrite, readJsonBody, requireScope } from "@aglyn/tenant-data-admin/server/api-v1-kit";
33
42
  import { CRM_LABEL_MAX, CRM_TEXT_MAX, CRM_TITLE_MAX, createPayload, crmCollection, crmCreateStamp, crmCustomUpdate, crmCustomView, crmRecordsBandRefusal, crmTimes, crmValidationFailed, isoFromMs, listCrm, memberError, readCrmCustomBody, readCrmSite, readEqualityFilters, readOptionalText, refuseUnknownKeys, updatePayload } from "./crm-shared.js";
34
43
  /** The company object as published. Every writable field appears here. */ function companyView(doc) {
35
- var _doc_data, _data_name, _data_domain, _data_website, _data_phone, _data_address, _data_industry, _data_ownerUid, _data_notes, _data_hostId;
44
+ var _doc_data, _data_name, _data_domain, _data_website, _data_phone, _data_address, _data_industry, _data_type, _data_rating, _data_ownership, _data_accountSource, _data_currency, _data_fax, _data_accountNumber, _data_site, _data_tickerSymbol, _data_sicCode, _data_shippingAddress, _data_ownerUid, _data_notes, _data_hostId;
36
45
  const data = (_doc_data = doc.data()) != null ? _doc_data : {};
37
46
  return _extends({
38
47
  id: doc.id,
@@ -41,8 +50,25 @@ import { CRM_LABEL_MAX, CRM_TEXT_MAX, CRM_TITLE_MAX, createPayload, crmCollectio
41
50
  domain: (_data_domain = data.domain) != null ? _data_domain : null,
42
51
  website: (_data_website = data.website) != null ? _data_website : null,
43
52
  phone: (_data_phone = data.phone) != null ? _data_phone : null,
53
+ // The billing address, under the name it always had.
44
54
  address: (_data_address = data.address) != null ? _data_address : null,
45
55
  industry: (_data_industry = data.industry) != null ? _data_industry : null,
56
+ // Salesforce's Account fields (AGL-3514).
57
+ type: (_data_type = data.type) != null ? _data_type : null,
58
+ rating: (_data_rating = data.rating) != null ? _data_rating : null,
59
+ ownership: (_data_ownership = data.ownership) != null ? _data_ownership : null,
60
+ accountSource: (_data_accountSource = data.accountSource) != null ? _data_accountSource : null,
61
+ annualRevenueCents: typeof data.annualRevenueCents === 'number' ? data.annualRevenueCents : null,
62
+ // `'usd'` when absent, as a deal's is.
63
+ currency: (_data_currency = data.currency) != null ? _data_currency : 'usd',
64
+ numberOfEmployees: typeof data.numberOfEmployees === 'number' ? data.numberOfEmployees : null,
65
+ fax: (_data_fax = data.fax) != null ? _data_fax : null,
66
+ accountNumber: (_data_accountNumber = data.accountNumber) != null ? _data_accountNumber : null,
67
+ site: (_data_site = data.site) != null ? _data_site : null,
68
+ tickerSymbol: (_data_tickerSymbol = data.tickerSymbol) != null ? _data_tickerSymbol : null,
69
+ sicCode: (_data_sicCode = data.sicCode) != null ? _data_sicCode : null,
70
+ shippingAddress: (_data_shippingAddress = data.shippingAddress) != null ? _data_shippingAddress : null,
71
+ parentCompanyId: crmCompanyParentId(data.parentCompanyId),
46
72
  ownerUid: (_data_ownerUid = data.ownerUid) != null ? _data_ownerUid : null,
47
73
  notes: (_data_notes = data.notes) != null ? _data_notes : null,
48
74
  // The org's company custom fields, keyed by field key (AGL-2661).
@@ -64,7 +90,11 @@ const COMPANY_WRITABLE = new Set([
64
90
  'ownerUid',
65
91
  'notes',
66
92
  'custom',
67
- 'mediaIds'
93
+ 'mediaIds',
94
+ // Salesforce's Account fields (AGL-3514).
95
+ ...CRM_COMPANY_PICKLIST_FIELDS.map((entry)=>entry.field),
96
+ ...CRM_COMPANY_ACCOUNT_FIELDS,
97
+ 'parentCompanyId'
68
98
  ]);
69
99
  /**
70
100
  * The writable half of a company, validated. `partial` separates PATCH from
@@ -79,6 +109,7 @@ const COMPANY_WRITABLE = new Set([
79
109
  */ function readCompanyInput(body, { partial }) {
80
110
  const errors = {};
81
111
  const values = {};
112
+ const picklists = {};
82
113
  const allowed = new Set(COMPANY_WRITABLE);
83
114
  if (!partial) allowed.add('consentSiteId');
84
115
  refuseUnknownKeys(body, allowed, 'company', errors);
@@ -146,8 +177,16 @@ const COMPANY_WRITABLE = new Set([
146
177
  values.address = normalizeAddress(body.address);
147
178
  }
148
179
  }
149
- const industry = readOptionalText(body, 'industry', CRM_LABEL_MAX, errors);
150
- if (industry !== undefined) values.industry = industry;
180
+ for (const { field } of CRM_COMPANY_PICKLIST_FIELDS){
181
+ const label = readOptionalText(body, field, CRM_LABEL_MAX, errors);
182
+ if (label !== undefined) picklists[field] = label;
183
+ }
184
+ const account = readCrmCompanyAccountFields(body);
185
+ Object.assign(errors, account.errors);
186
+ values.account = account.values;
187
+ const parentCompanyId = readOptionalText(body, 'parentCompanyId', CRM_LABEL_MAX, errors);
188
+ if (parentCompanyId && parentCompanyId.includes('/')) errors.parentCompanyId = 'No such company';
189
+ else if (parentCompanyId !== undefined) values.parentCompanyId = parentCompanyId;
151
190
  const ownerUid = readOptionalText(body, 'ownerUid', CRM_LABEL_MAX, errors);
152
191
  if (ownerUid !== undefined) values.ownerUid = ownerUid;
153
192
  const notes = readOptionalText(body, 'notes', CRM_TEXT_MAX, errors);
@@ -162,7 +201,48 @@ const COMPANY_WRITABLE = new Set([
162
201
  return Object.keys(errors).length ? {
163
202
  errors
164
203
  } : {
165
- values
204
+ values,
205
+ picklists
206
+ };
207
+ }
208
+ /** The org's list behind every company picklist field the body names. */ async function readNamedPicklists(ctx, named, created) {
209
+ // A create starts every field from its list's default, so it reads them all.
210
+ const ids = [
211
+ ...new Set(CRM_COMPANY_PICKLIST_FIELDS.filter((entry)=>created || named[entry.field] !== undefined).map((entry)=>entry.picklistId))
212
+ ];
213
+ const lists = await Promise.all(ids.map((id)=>readCrmPicklist(ctx.firestore, ctx.orgId, id)));
214
+ return Object.fromEntries(ids.map((id, at)=>[
215
+ id,
216
+ lists[at]
217
+ ]));
218
+ }
219
+ /**
220
+ * The picklist values and the parent a write stores, or the 400's fields:
221
+ * each label judged against its list with the company's `current` value
222
+ * kept, and a parent that is this company, one below it, or none the
223
+ * organization holds refused by name.
224
+ */ async function judgeCompanyReferences(ctx, collection, input, options) {
225
+ const created = options.companyId === null;
226
+ const lists = await readNamedPicklists(ctx, input.picklists, created);
227
+ const judged = judgeCrmCompanyPicklists(lists, input.picklists, {
228
+ current: options.current,
229
+ created
230
+ });
231
+ const errors = _extends({}, judged.errors);
232
+ const parentId = input.parentCompanyId;
233
+ if (parentId && parentId !== crmCompanyParentId(options.current['parentCompanyId'])) {
234
+ const refusal = await crmCompanyParentRefusal(options.companyId, parentId, async (id)=>{
235
+ const snapshot = await collection.doc(id).get();
236
+ return snapshot.exists ? {
237
+ parentCompanyId: crmCompanyParentId(snapshot.get('parentCompanyId'))
238
+ } : null;
239
+ });
240
+ if (refusal) errors.parentCompanyId = refusal;
241
+ }
242
+ return Object.keys(errors).length ? {
243
+ errors
244
+ } : {
245
+ picklists: judged.values
166
246
  };
167
247
  }
168
248
  /**
@@ -185,13 +265,24 @@ const COMPANY_WRITABLE = new Set([
185
265
  if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors);
186
266
  const customValues = custom && 'values' in custom ? custom.values : {};
187
267
  const collection = crmCollection(ctx, CRM_COLLECTIONS.companies);
268
+ // The org's lists and the parent (AGL-3514), above the claim with the
269
+ // other deterministic 400s.
270
+ const references = await judgeCompanyReferences(ctx, collection, {
271
+ picklists: parsed.picklists,
272
+ parentCompanyId: parsed.values.parentCompanyId
273
+ }, {
274
+ companyId: null,
275
+ current: {}
276
+ });
277
+ if ('errors' in references) return crmValidationFailed(ctx, 'company', references.errors);
188
278
  const claimed = await claimWrite(ctx, '*', request.headers.get('Idempotency-Key'), 'companies');
189
279
  if ('replay' in claimed) return claimed.replay;
190
280
  const { claim } = claimed;
191
281
  try {
192
- const _parsed_values = parsed.values, { name, domain } = _parsed_values, rest = _object_without_properties_loose(_parsed_values, [
282
+ const _parsed_values = parsed.values, { name, domain, account } = _parsed_values, rest = _object_without_properties_loose(_parsed_values, [
193
283
  "name",
194
- "domain"
284
+ "domain",
285
+ "account"
195
286
  ]);
196
287
  if (domain) {
197
288
  const existing = await collection.where('domain', '==', domain).limit(1).get();
@@ -215,7 +306,7 @@ const COMPANY_WRITABLE = new Set([
215
306
  const id = createResourceUid();
216
307
  const record = _extends({}, nameSearchFields(name != null ? name : ''), createPayload(_extends({
217
308
  domain
218
- }, rest)), Object.keys(customValues).length ? {
309
+ }, rest, references.picklists, account)), Object.keys(customValues).length ? {
219
310
  custom: createPayload(customValues)
220
311
  } : {}, crmCreateStamp(ctx, site.siteId));
221
312
  // What the console's Companies list searches and filters by (AGL-3321).
@@ -233,6 +324,7 @@ const COMPANY_WRITABLE = new Set([
233
324
  }
234
325
  }
235
326
  /** `PATCH /v1/companies/{id}` — no key, for `updateContact`'s reason. */ async function updateCompany(request, ctx, ref) {
327
+ var _snap_data;
236
328
  const body = await readJsonBody(request);
237
329
  const parsed = readCompanyInput(body, {
238
330
  partial: true
@@ -249,9 +341,18 @@ const COMPANY_WRITABLE = new Set([
249
341
  if (Object.keys(owner).length) return crmValidationFailed(ctx, 'company', owner);
250
342
  const custom = await readCrmCustomBody(ctx, body, 'company');
251
343
  if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors);
252
- const _parsed_values = parsed.values, { name, domain } = _parsed_values, rest = _object_without_properties_loose(_parsed_values, [
344
+ const references = await judgeCompanyReferences(ctx, ref.parent, {
345
+ picklists: parsed.picklists,
346
+ parentCompanyId: parsed.values.parentCompanyId
347
+ }, {
348
+ companyId: ref.id,
349
+ current: (_snap_data = snap.data()) != null ? _snap_data : {}
350
+ });
351
+ if ('errors' in references) return crmValidationFailed(ctx, 'company', references.errors);
352
+ const _parsed_values = parsed.values, { name, domain, account } = _parsed_values, rest = _object_without_properties_loose(_parsed_values, [
253
353
  "name",
254
- "domain"
354
+ "domain",
355
+ "account"
255
356
  ]);
256
357
  if (domain && domain !== snap.get('domain')) {
257
358
  const existing = await ref.parent.where('domain', '==', domain).limit(1).get();
@@ -265,13 +366,14 @@ const COMPANY_WRITABLE = new Set([
265
366
  }
266
367
  const update = _extends({}, name !== undefined ? nameSearchFields(name) : {}, updatePayload(_extends({
267
368
  domain
268
- }, rest)), custom && 'values' in custom ? crmCustomUpdate(custom.values) : {});
369
+ }, rest, references.picklists, account)), custom && 'values' in custom ? crmCustomUpdate(custom.values) : {});
269
370
  // An empty body is a no-op answered with the current company.
270
371
  if (Object.keys(update).length > 0) {
271
372
  await ref.update(_extends({}, update, {
272
373
  updatedAt: Timestamp.now()
273
374
  }));
274
- // What the console's Companies list searches (AGL-3321).
375
+ // What the console's Companies list searches (AGL-3321) and filters
376
+ // by (AGL-3514).
275
377
  await restampCrmListFieldsAt(ref, 'companies');
276
378
  }
277
379
  return apiJson(companyView(await ref.get()), {
@@ -282,7 +384,8 @@ const COMPANY_WRITABLE = new Set([
282
384
  * `DELETE /v1/companies/{id}` — the company alone. The deals, tasks and
283
385
  * activities filed against it keep their `companyId`; they are records of
284
386
  * their own, and a delete that cascaded through them would erase a sales
285
- * history because somebody removed a duplicate account.
387
+ * history because somebody removed a duplicate account. The companies
388
+ * under it keep everything but their `parentCompanyId` (AGL-3514).
286
389
  */ async function deleteCompany(request, ctx, ref) {
287
390
  const claimed = await claimWrite(ctx, '*', request.headers.get('Idempotency-Key'), 'company-deletes');
288
391
  if ('replay' in claimed) return claimed.replay;
@@ -296,6 +399,12 @@ const COMPANY_WRITABLE = new Set([
296
399
  headers: ctx.headers
297
400
  });
298
401
  }
402
+ // The companies under it stand on their own (AGL-3514): their parent is
403
+ // cleared, a batch at a time, before it goes.
404
+ for(;;){
405
+ const pass = await detachChildCompanies(ctx.firestore, ref.parent, ref.id);
406
+ if (!pass.moreRemain) break;
407
+ }
299
408
  await ref.delete();
300
409
  const view = {
301
410
  id: ref.id,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/server/api-v1/crm-companies.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 * `/v1/companies` (AGL-2606) — the organizations behind the people.\n *\n * A company is keyed, in practice, by its domain: two contacts at\n * `example.com` work for one company, and the console's auto-association\n * (`companyDomainForEmail`) files them under it by that string. So the\n * domain is normalized exactly as the console stores it, a second company on\n * a domain already held is a `409 company_exists` naming the first — the\n * contact create's own rule for a second row on one email — and `?domain=`\n * is the lookup a sync starts with.\n */\nimport { nameSearchFields } from '@aglyn/aglyn/app-utils/name-search'\nimport {\n CRM_COLLECTIONS,\n CRM_MEDIA_IDS_MAX,\n createResourceUid,\n crmNewRecordListFields,\n normalizeAddress,\n normalizeCompanyDomain,\n normalizeCrmMediaIds,\n normalizePhone,\n} from '@aglyn/aglyn/server'\nimport { apiJson, ApiErrors, restampCrmListFieldsAt } from '@aglyn/tenant-data-admin'\nimport { Timestamp } from 'firebase-admin/firestore'\nimport {\n type ApiV1Context,\n claimWrite,\n readJsonBody,\n requireScope,\n} from '@aglyn/tenant-data-admin/server/api-v1-kit'\nimport {\n type Clearable,\n CRM_LABEL_MAX,\n CRM_TEXT_MAX,\n CRM_TITLE_MAX,\n createPayload,\n crmCollection,\n crmCreateStamp,\n crmCustomUpdate,\n crmCustomView,\n crmRecordsBandRefusal,\n crmTimes,\n crmValidationFailed,\n isoFromMs,\n listCrm,\n memberError,\n readCrmCustomBody,\n readCrmSite,\n readEqualityFilters,\n readOptionalText,\n refuseUnknownKeys,\n updatePayload,\n} from './crm-shared'\n\n/** The company object as published. Every writable field appears here. */\nfunction companyView(doc: FirebaseFirestore.DocumentSnapshot) {\n const data = doc.data() ?? {}\n return {\n id: doc.id,\n object: 'company',\n name: data.name ?? null,\n domain: data.domain ?? null,\n website: data.website ?? null,\n phone: data.phone ?? null,\n address: data.address ?? null,\n industry: data.industry ?? null,\n ownerUid: data.ownerUid ?? null,\n notes: data.notes ?? null,\n // The org's company custom fields, keyed by field key (AGL-2661).\n custom: crmCustomView(data),\n // When the earliest open task against the company is due — see\n // `CrmDeal.nextTaskAtMs`. Read-only: the tasks resource maintains it.\n nextTaskAt: isoFromMs(data.nextTaskAtMs),\n mediaIds: normalizeCrmMediaIds(data.mediaIds),\n siteId: data.hostId ?? null,\n ...crmTimes(data),\n }\n}\n\nconst COMPANY_WRITABLE = new Set([\n 'name',\n 'domain',\n 'website',\n 'phone',\n 'address',\n 'industry',\n 'ownerUid',\n 'notes',\n 'custom',\n 'mediaIds',\n])\n\ninterface CompanyInput {\n name?: string\n domain?: Clearable<string>\n website?: Clearable<string>\n phone?: Clearable<string>\n address?: Clearable<ReturnType<typeof normalizeAddress>>\n industry?: Clearable<string>\n ownerUid?: Clearable<string>\n notes?: Clearable<string>\n /** Org-library files attached to the company (AGL-2662), by media id. */\n mediaIds?: string[]\n}\n\n/**\n * The writable half of a company, validated. `partial` separates PATCH from\n * POST as every reader in this API does: a create needs a name, an update\n * may send one field alone. Unknown keys are named, never dropped.\n *\n * `domain` and `phone` go through the console's own normalizers so the API\n * cannot store a value the console would never have written, and a value\n * that does not survive normalization names the field rather than storing\n * the raw string — a raw domain would never match the auto-association, and\n * a raw phone is the unusable half-number `normalizePhone` exists to end.\n */\nfunction readCompanyInput(\n body: Record<string, unknown>,\n { partial }: { partial: boolean },\n): { values: CompanyInput } | { errors: Record<string, string> } {\n const errors: Record<string, string> = {}\n const values: CompanyInput = {}\n const allowed = new Set(COMPANY_WRITABLE)\n if (!partial) allowed.add('consentSiteId')\n refuseUnknownKeys(body, allowed, 'company', errors)\n\n if (body.name !== undefined || !partial) {\n const name = String(body.name ?? '')\n .trim()\n .slice(0, CRM_TITLE_MAX)\n if (name) values.name = name\n else errors.name = partial ? 'Must not be empty' : 'A name is required'\n }\n\n\n if (body.mediaIds !== undefined) {\n if (!Array.isArray(body.mediaIds)) {\n errors.mediaIds = 'Must be an array of media ids'\n } else if (body.mediaIds.length > CRM_MEDIA_IDS_MAX) {\n errors.mediaIds = `At most ${CRM_MEDIA_IDS_MAX} files may be attached`\n } else {\n // The SAME normalizer the console card writes through, so the API\n // cannot store a list the console would refuse. An empty array is\n // legal and clears the attachments.\n values.mediaIds = normalizeCrmMediaIds(body.mediaIds)\n }\n }\n\n const domain = readOptionalText(body, 'domain', CRM_TITLE_MAX, errors)\n if (domain) {\n const normalized = normalizeCompanyDomain(domain)\n if (normalized) values.domain = normalized\n else errors.domain = 'Must be a domain name, like example.com'\n } else if (domain === null) {\n values.domain = null\n }\n\n const website = readOptionalText(body, 'website', CRM_TITLE_MAX * 4, errors)\n if (website) {\n // A bare `example.com` is what people paste; stored with the scheme so the\n // console can render it as a link without guessing one.\n const withScheme = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(website)\n ? website\n : `https://${website}`\n let parsed: URL | null\n try {\n parsed = new URL(withScheme)\n } catch {\n parsed = null\n }\n if (parsed && /^https?:$/.test(parsed.protocol) && normalizeCompanyDomain(parsed.hostname)) {\n values.website = parsed.toString()\n } else {\n errors.website = 'Must be a web address, like https://example.com'\n }\n } else if (website === null) {\n values.website = null\n }\n\n const phone = readOptionalText(body, 'phone', CRM_LABEL_MAX, errors)\n if (phone) {\n const normalized = normalizePhone(phone)\n if (normalized) values.phone = normalized\n else errors.phone = 'Must be a phone number with a country code, like +15125550123'\n } else if (phone === null) {\n values.phone = null\n }\n\n if (body.address !== undefined) {\n if (body.address === null) {\n values.address = null\n } else if (typeof body.address !== 'object' || Array.isArray(body.address)) {\n errors.address = 'Must be an address object'\n } else {\n // A blank address normalizes to `null`, which clears — an object of\n // empty strings must not read as \"has an address\".\n values.address = normalizeAddress(body.address as never)\n }\n }\n\n const industry = readOptionalText(body, 'industry', CRM_LABEL_MAX, errors)\n if (industry !== undefined) values.industry = industry\n\n const ownerUid = readOptionalText(body, 'ownerUid', CRM_LABEL_MAX, errors)\n if (ownerUid !== undefined) values.ownerUid = ownerUid\n\n const notes = readOptionalText(body, 'notes', CRM_TEXT_MAX, errors)\n if (notes !== undefined) values.notes = notes\n\n // `custom` is shape-checked here and judged against the org's\n // definitions by the writers, which is where the read is paid.\n if (body.custom !== undefined) {\n if (!body.custom || typeof body.custom !== 'object' || Array.isArray(body.custom)) {\n errors.custom = 'Must be an object of field values keyed by field key'\n }\n }\n\n return Object.keys(errors).length ? { errors } : { values }\n}\n\n/**\n * `POST /v1/companies`. Claimed first and released on the duplicate, the\n * ordering `createContact` argues for: a refusal that clears when the\n * duplicate is removed must not burn the key the retry will carry.\n */\nasync function createCompany(\n request: Request,\n ctx: ApiV1Context,\n): Promise<Response> {\n const body = await readJsonBody(request)\n const parsed = readCompanyInput(body, { partial: false })\n if ('errors' in parsed) return crmValidationFailed(ctx, 'company', parsed.errors)\n const site = readCrmSite(ctx, 'company', body)\n if ('response' in site) return site.response\n const owner = await memberError(ctx, 'ownerUid', parsed.values.ownerUid)\n if (Object.keys(owner).length) return crmValidationFailed(ctx, 'company', owner)\n // Judged against the org's company definitions, above the claim like\n // every other deterministic 400 (AGL-2661).\n const custom = await readCrmCustomBody(ctx, body, 'company')\n if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors)\n const customValues = custom && 'values' in custom ? custom.values : {}\n\n const collection = crmCollection(ctx, CRM_COLLECTIONS.companies)\n const claimed = await claimWrite(\n ctx,\n '*',\n request.headers.get('Idempotency-Key'),\n 'companies',\n )\n if ('replay' in claimed) return claimed.replay\n const { claim } = claimed\n\n try {\n const { name, domain, ...rest } = parsed.values\n if (domain) {\n const existing = await collection.where('domain', '==', domain).limit(1).get()\n if (!existing.empty) {\n await claim.release()\n return ApiErrors.conflict({\n message: `A company with this domain already exists (${existing.docs[0].id}). Update it instead.`,\n code: 'company_exists',\n headers: ctx.headers,\n })\n }\n }\n // The records band (AGL-2611), after the duplicate check for the reason\n // the claim ordering gives: a refusal that clears when the band is raised\n // must not burn the key the retry will carry.\n const bandFull = await crmRecordsBandRefusal(ctx)\n if (bandFull) {\n await claim.release()\n return bandFull\n }\n const id = createResourceUid()\n const record: Record<string, unknown> = {\n // `nameLower`/`nameTokens` travel with the name: the console's company\n // list searches the collection, not the page it fetched.\n ...nameSearchFields(name ?? ''),\n ...createPayload({ domain, ...rest }),\n // An empty map writes no `custom` key at all; a `null` inside one is\n // an explicit clear a fresh record has no use for.\n ...(Object.keys(customValues).length\n ? { custom: createPayload(customValues) }\n : {}),\n ...crmCreateStamp(ctx, site.siteId),\n }\n // What the console's Companies list searches and filters by (AGL-3321).\n await collection.doc(id).create({ ...record, ...crmNewRecordListFields('companies', record) })\n const view = companyView(await collection.doc(id).get())\n // Stored as 200 so a replay is distinguishable from the fresh 201.\n await claim.record(200, view)\n return apiJson(view, { status: 201, headers: ctx.headers })\n } catch (error) {\n await claim.release()\n throw error\n }\n}\n\n/** `PATCH /v1/companies/{id}` — no key, for `updateContact`'s reason. */\nasync function updateCompany(\n request: Request,\n ctx: ApiV1Context,\n ref: FirebaseFirestore.DocumentReference,\n): Promise<Response> {\n const body = await readJsonBody(request)\n const parsed = readCompanyInput(body, { partial: true })\n if ('errors' in parsed) return crmValidationFailed(ctx, 'company', parsed.errors)\n const snap = await ref.get()\n if (!snap.exists) {\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n const owner = await memberError(ctx, 'ownerUid', parsed.values.ownerUid)\n if (Object.keys(owner).length) return crmValidationFailed(ctx, 'company', owner)\n const custom = await readCrmCustomBody(ctx, body, 'company')\n if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors)\n\n const { name, domain, ...rest } = parsed.values\n if (domain && domain !== snap.get('domain')) {\n const existing = await ref.parent.where('domain', '==', domain).limit(1).get()\n if (!existing.empty && existing.docs[0].id !== ref.id) {\n return ApiErrors.conflict({\n message: `A company with this domain already exists (${existing.docs[0].id}).`,\n code: 'company_exists',\n headers: ctx.headers,\n })\n }\n }\n const update: Record<string, unknown> = {\n ...(name !== undefined ? nameSearchFields(name) : {}),\n ...updatePayload({ domain, ...rest }),\n ...(custom && 'values' in custom ? crmCustomUpdate(custom.values) : {}),\n }\n // An empty body is a no-op answered with the current company.\n if (Object.keys(update).length > 0) {\n await ref.update({ ...update, updatedAt: Timestamp.now() })\n // What the console's Companies list searches (AGL-3321).\n await restampCrmListFieldsAt(ref, 'companies')\n }\n return apiJson(companyView(await ref.get()), { headers: ctx.headers })\n}\n\n/**\n * `DELETE /v1/companies/{id}` — the company alone. The deals, tasks and\n * activities filed against it keep their `companyId`; they are records of\n * their own, and a delete that cascaded through them would erase a sales\n * history because somebody removed a duplicate account.\n */\nasync function deleteCompany(\n request: Request,\n ctx: ApiV1Context,\n ref: FirebaseFirestore.DocumentReference,\n): Promise<Response> {\n const claimed = await claimWrite(\n ctx,\n '*',\n request.headers.get('Idempotency-Key'),\n 'company-deletes',\n )\n if ('replay' in claimed) return claimed.replay\n const { claim } = claimed\n try {\n const snap = await ref.get()\n if (!snap.exists) {\n await claim.release()\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n await ref.delete()\n const view = { id: ref.id, object: 'company', deleted: true }\n await claim.record(200, view)\n return apiJson(view, { headers: ctx.headers })\n } catch (error) {\n await claim.release()\n throw error\n }\n}\n\n/**\n * `GET /v1/companies` filters. `domain` is normalized exactly as the write\n * stores it, so `?domain=https://www.Example.com/about` finds `example.com`; a\n * value that is not a domain at all is a `400`, not an empty page, for the\n * reason `listContacts` gives about `?email=`.\n */\nasync function listCompanies(\n ctx: ApiV1Context,\n collection: FirebaseFirestore.CollectionReference,\n url: URL,\n): Promise<Response> {\n const rawDomain = url.searchParams.get('domain')\n const filters = readEqualityFilters(url, ['ownerUid'])\n if (rawDomain !== null && rawDomain.trim() !== '') {\n const domain = normalizeCompanyDomain(rawDomain)\n if (!domain) {\n return crmValidationFailed(ctx, 'company filter', {\n domain: 'Must be a domain name, like example.com',\n })\n }\n // The domain is unique, so it is the clause that goes to Firestore.\n filters.unshift({ field: 'domain', value: domain })\n }\n return listCrm(ctx, collection, url, filters, companyView)\n}\n\nexport async function handleCompanies(\n request: Request,\n ctx: ApiV1Context,\n segments: string[],\n url: URL,\n): Promise<Response> {\n const collection = crmCollection(ctx, CRM_COLLECTIONS.companies)\n const [, companyId] = segments\n\n if (!companyId) {\n if (request.method === 'GET') {\n const denied = requireScope(ctx, 'crm:read')\n if (denied) return denied\n return listCompanies(ctx, collection, url)\n }\n if (request.method === 'POST') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return createCompany(request, ctx)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, POST' },\n })\n }\n\n const ref = collection.doc(companyId)\n if (request.method === 'GET') {\n const denied = requireScope(ctx, 'crm:read')\n if (denied) return denied\n const snap = await ref.get()\n if (!snap.exists) {\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n return apiJson(companyView(snap), { headers: ctx.headers })\n }\n if (request.method === 'PATCH') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return updateCompany(request, ctx, ref)\n }\n if (request.method === 'DELETE') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return deleteCompany(request, ctx, ref)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, PATCH, DELETE' },\n })\n}\n"],"names":["nameSearchFields","CRM_COLLECTIONS","CRM_MEDIA_IDS_MAX","createResourceUid","crmNewRecordListFields","normalizeAddress","normalizeCompanyDomain","normalizeCrmMediaIds","normalizePhone","apiJson","ApiErrors","restampCrmListFieldsAt","Timestamp","claimWrite","readJsonBody","requireScope","CRM_LABEL_MAX","CRM_TEXT_MAX","CRM_TITLE_MAX","createPayload","crmCollection","crmCreateStamp","crmCustomUpdate","crmCustomView","crmRecordsBandRefusal","crmTimes","crmValidationFailed","isoFromMs","listCrm","memberError","readCrmCustomBody","readCrmSite","readEqualityFilters","readOptionalText","refuseUnknownKeys","updatePayload","companyView","doc","data","id","object","name","domain","website","phone","address","industry","ownerUid","notes","custom","nextTaskAt","nextTaskAtMs","mediaIds","siteId","hostId","COMPANY_WRITABLE","Set","readCompanyInput","body","partial","errors","values","allowed","add","undefined","String","trim","slice","Array","isArray","length","normalized","withScheme","test","parsed","URL","protocol","hostname","toString","Object","keys","createCompany","request","ctx","site","response","owner","customValues","collection","companies","claimed","headers","get","replay","claim","rest","existing","where","limit","empty","release","conflict","message","docs","code","bandFull","record","create","view","status","error","updateCompany","ref","snap","exists","notFound","parent","update","updatedAt","now","deleteCompany","delete","deleted","listCompanies","url","rawDomain","searchParams","filters","unshift","field","value","handleCompanies","segments","companyId","method","denied","methodNotAllowed","Allow"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/server/api-v1/crm-companies.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 * `/v1/companies` (AGL-2606) — the organizations behind the people.\n *\n * A company is keyed, in practice, by its domain: two contacts at\n * `example.com` work for one company, and the console's auto-association\n * (`companyDomainForEmail`) files them under it by that string. So the\n * domain is normalized exactly as the console stores it, a second company on\n * a domain already held is a `409 company_exists` naming the first — the\n * contact create's own rule for a second row on one email — and `?domain=`\n * is the lookup a sync starts with.\n *\n * Salesforce's Account fields (AGL-3514) ride the same object: Type,\n * Industry, Rating, Ownership and Account Source are labels of the org's\n * lists — any other value is a 400 naming what the list allows, and the\n * value a company already holds is kept — the rest are read through\n * `readCrmCompanyAccountFields`, and `parentCompanyId` names another\n * company of the organization that is not this one or below it.\n */\nimport { nameSearchFields } from '@aglyn/aglyn/app-utils/name-search'\nimport {\n CRM_COLLECTIONS,\n CRM_COMPANY_ACCOUNT_FIELDS,\n CRM_COMPANY_PICKLIST_FIELDS,\n CRM_MEDIA_IDS_MAX,\n type CrmCompanyAccountField,\n type CrmCompanyPicklistField,\n type CrmPicklist,\n type CrmPicklistId,\n createResourceUid,\n crmCompanyParentId,\n crmCompanyParentRefusal,\n crmNewRecordListFields,\n judgeCrmCompanyPicklists,\n normalizeAddress,\n normalizeCompanyDomain,\n normalizeCrmMediaIds,\n normalizePhone,\n readCrmCompanyAccountFields,\n} from '@aglyn/aglyn/server'\nimport { detachChildCompanies } from '../company-children'\nimport { readCrmPicklist } from '../read-picklist'\nimport { apiJson, ApiErrors, restampCrmListFieldsAt } from '@aglyn/tenant-data-admin'\nimport { Timestamp } from 'firebase-admin/firestore'\nimport {\n type ApiV1Context,\n claimWrite,\n readJsonBody,\n requireScope,\n} from '@aglyn/tenant-data-admin/server/api-v1-kit'\nimport {\n type Clearable,\n CRM_LABEL_MAX,\n CRM_TEXT_MAX,\n CRM_TITLE_MAX,\n createPayload,\n crmCollection,\n crmCreateStamp,\n crmCustomUpdate,\n crmCustomView,\n crmRecordsBandRefusal,\n crmTimes,\n crmValidationFailed,\n isoFromMs,\n listCrm,\n memberError,\n readCrmCustomBody,\n readCrmSite,\n readEqualityFilters,\n readOptionalText,\n refuseUnknownKeys,\n updatePayload,\n} from './crm-shared'\n\n/** The company object as published. Every writable field appears here. */\nfunction companyView(doc: FirebaseFirestore.DocumentSnapshot) {\n const data = doc.data() ?? {}\n return {\n id: doc.id,\n object: 'company',\n name: data.name ?? null,\n domain: data.domain ?? null,\n website: data.website ?? null,\n phone: data.phone ?? null,\n // The billing address, under the name it always had.\n address: data.address ?? null,\n industry: data.industry ?? null,\n // Salesforce's Account fields (AGL-3514).\n type: data.type ?? null,\n rating: data.rating ?? null,\n ownership: data.ownership ?? null,\n accountSource: data.accountSource ?? null,\n annualRevenueCents: typeof data.annualRevenueCents === 'number' ? data.annualRevenueCents : null,\n // `'usd'` when absent, as a deal's is.\n currency: data.currency ?? 'usd',\n numberOfEmployees: typeof data.numberOfEmployees === 'number' ? data.numberOfEmployees : null,\n fax: data.fax ?? null,\n accountNumber: data.accountNumber ?? null,\n site: data.site ?? null,\n tickerSymbol: data.tickerSymbol ?? null,\n sicCode: data.sicCode ?? null,\n shippingAddress: data.shippingAddress ?? null,\n parentCompanyId: crmCompanyParentId(data.parentCompanyId),\n ownerUid: data.ownerUid ?? null,\n notes: data.notes ?? null,\n // The org's company custom fields, keyed by field key (AGL-2661).\n custom: crmCustomView(data),\n // When the earliest open task against the company is due — see\n // `CrmDeal.nextTaskAtMs`. Read-only: the tasks resource maintains it.\n nextTaskAt: isoFromMs(data.nextTaskAtMs),\n mediaIds: normalizeCrmMediaIds(data.mediaIds),\n siteId: data.hostId ?? null,\n ...crmTimes(data),\n }\n}\n\nconst COMPANY_WRITABLE = new Set([\n 'name',\n 'domain',\n 'website',\n 'phone',\n 'address',\n 'industry',\n 'ownerUid',\n 'notes',\n 'custom',\n 'mediaIds',\n // Salesforce's Account fields (AGL-3514).\n ...CRM_COMPANY_PICKLIST_FIELDS.map((entry) => entry.field),\n ...CRM_COMPANY_ACCOUNT_FIELDS,\n 'parentCompanyId',\n])\n\ninterface CompanyInput {\n name?: string\n domain?: Clearable<string>\n website?: Clearable<string>\n phone?: Clearable<string>\n address?: Clearable<ReturnType<typeof normalizeAddress>>\n ownerUid?: Clearable<string>\n notes?: Clearable<string>\n /** Org-library files attached to the company (AGL-2662), by media id. */\n mediaIds?: string[]\n /** Salesforce's other account fields, normalized (AGL-3514). */\n account?: Partial<Record<CrmCompanyAccountField, unknown>>\n parentCompanyId?: Clearable<string>\n}\n\n/**\n * The picklist fields as sent (AGL-3514), apart from the values stored as\n * read: the writers judge them against the org's lists, which is where\n * that read is paid.\n */\ntype CompanyPicklistInput = Partial<Record<CrmCompanyPicklistField, string | null>>\n\n/**\n * The writable half of a company, validated. `partial` separates PATCH from\n * POST as every reader in this API does: a create needs a name, an update\n * may send one field alone. Unknown keys are named, never dropped.\n *\n * `domain` and `phone` go through the console's own normalizers so the API\n * cannot store a value the console would never have written, and a value\n * that does not survive normalization names the field rather than storing\n * the raw string — a raw domain would never match the auto-association, and\n * a raw phone is the unusable half-number `normalizePhone` exists to end.\n */\nfunction readCompanyInput(\n body: Record<string, unknown>,\n { partial }: { partial: boolean },\n): { values: CompanyInput; picklists: CompanyPicklistInput } | { errors: Record<string, string> } {\n const errors: Record<string, string> = {}\n const values: CompanyInput = {}\n const picklists: CompanyPicklistInput = {}\n const allowed = new Set(COMPANY_WRITABLE)\n if (!partial) allowed.add('consentSiteId')\n refuseUnknownKeys(body, allowed, 'company', errors)\n\n if (body.name !== undefined || !partial) {\n const name = String(body.name ?? '')\n .trim()\n .slice(0, CRM_TITLE_MAX)\n if (name) values.name = name\n else errors.name = partial ? 'Must not be empty' : 'A name is required'\n }\n\n\n if (body.mediaIds !== undefined) {\n if (!Array.isArray(body.mediaIds)) {\n errors.mediaIds = 'Must be an array of media ids'\n } else if (body.mediaIds.length > CRM_MEDIA_IDS_MAX) {\n errors.mediaIds = `At most ${CRM_MEDIA_IDS_MAX} files may be attached`\n } else {\n // The SAME normalizer the console card writes through, so the API\n // cannot store a list the console would refuse. An empty array is\n // legal and clears the attachments.\n values.mediaIds = normalizeCrmMediaIds(body.mediaIds)\n }\n }\n\n const domain = readOptionalText(body, 'domain', CRM_TITLE_MAX, errors)\n if (domain) {\n const normalized = normalizeCompanyDomain(domain)\n if (normalized) values.domain = normalized\n else errors.domain = 'Must be a domain name, like example.com'\n } else if (domain === null) {\n values.domain = null\n }\n\n const website = readOptionalText(body, 'website', CRM_TITLE_MAX * 4, errors)\n if (website) {\n // A bare `example.com` is what people paste; stored with the scheme so the\n // console can render it as a link without guessing one.\n const withScheme = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(website)\n ? website\n : `https://${website}`\n let parsed: URL | null\n try {\n parsed = new URL(withScheme)\n } catch {\n parsed = null\n }\n if (parsed && /^https?:$/.test(parsed.protocol) && normalizeCompanyDomain(parsed.hostname)) {\n values.website = parsed.toString()\n } else {\n errors.website = 'Must be a web address, like https://example.com'\n }\n } else if (website === null) {\n values.website = null\n }\n\n const phone = readOptionalText(body, 'phone', CRM_LABEL_MAX, errors)\n if (phone) {\n const normalized = normalizePhone(phone)\n if (normalized) values.phone = normalized\n else errors.phone = 'Must be a phone number with a country code, like +15125550123'\n } else if (phone === null) {\n values.phone = null\n }\n\n if (body.address !== undefined) {\n if (body.address === null) {\n values.address = null\n } else if (typeof body.address !== 'object' || Array.isArray(body.address)) {\n errors.address = 'Must be an address object'\n } else {\n // A blank address normalizes to `null`, which clears — an object of\n // empty strings must not read as \"has an address\".\n values.address = normalizeAddress(body.address as never)\n }\n }\n\n for (const { field } of CRM_COMPANY_PICKLIST_FIELDS) {\n const label = readOptionalText(body, field, CRM_LABEL_MAX, errors)\n if (label !== undefined) picklists[field] = label\n }\n const account = readCrmCompanyAccountFields(body)\n Object.assign(errors, account.errors)\n values.account = account.values\n\n const parentCompanyId = readOptionalText(body, 'parentCompanyId', CRM_LABEL_MAX, errors)\n if (parentCompanyId && parentCompanyId.includes('/')) errors.parentCompanyId = 'No such company'\n else if (parentCompanyId !== undefined) values.parentCompanyId = parentCompanyId\n\n const ownerUid = readOptionalText(body, 'ownerUid', CRM_LABEL_MAX, errors)\n if (ownerUid !== undefined) values.ownerUid = ownerUid\n\n const notes = readOptionalText(body, 'notes', CRM_TEXT_MAX, errors)\n if (notes !== undefined) values.notes = notes\n\n // `custom` is shape-checked here and judged against the org's\n // definitions by the writers, which is where the read is paid.\n if (body.custom !== undefined) {\n if (!body.custom || typeof body.custom !== 'object' || Array.isArray(body.custom)) {\n errors.custom = 'Must be an object of field values keyed by field key'\n }\n }\n\n return Object.keys(errors).length ? { errors } : { values, picklists }\n}\n\n/** The org's list behind every company picklist field the body names. */\nasync function readNamedPicklists(\n ctx: ApiV1Context,\n named: CompanyPicklistInput,\n created: boolean,\n): Promise<Partial<Record<CrmPicklistId, CrmPicklist>>> {\n // A create starts every field from its list's default, so it reads them all.\n const ids = [\n ...new Set(\n CRM_COMPANY_PICKLIST_FIELDS.filter((entry) => created || named[entry.field] !== undefined).map(\n (entry) => entry.picklistId,\n ),\n ),\n ]\n const lists = await Promise.all(ids.map((id) => readCrmPicklist(ctx.firestore, ctx.orgId, id)))\n return Object.fromEntries(ids.map((id, at) => [id, lists[at]]))\n}\n\n/**\n * The picklist values and the parent a write stores, or the 400's fields:\n * each label judged against its list with the company's `current` value\n * kept, and a parent that is this company, one below it, or none the\n * organization holds refused by name.\n */\nasync function judgeCompanyReferences(\n ctx: ApiV1Context,\n collection: FirebaseFirestore.CollectionReference,\n input: { picklists: CompanyPicklistInput; parentCompanyId?: Clearable<string> },\n options: { companyId: string | null; current: Record<string, unknown> },\n): Promise<\n | { picklists: Partial<Record<CrmCompanyPicklistField, string | null>> }\n | { errors: Record<string, string> }\n> {\n const created = options.companyId === null\n const lists = await readNamedPicklists(ctx, input.picklists, created)\n const judged = judgeCrmCompanyPicklists(lists, input.picklists, {\n current: options.current,\n created,\n })\n const errors = { ...judged.errors }\n const parentId = input.parentCompanyId\n if (parentId && parentId !== crmCompanyParentId(options.current['parentCompanyId'])) {\n const refusal = await crmCompanyParentRefusal(options.companyId, parentId, async (id) => {\n const snapshot = await collection.doc(id).get()\n return snapshot.exists ? { parentCompanyId: crmCompanyParentId(snapshot.get('parentCompanyId')) } : null\n })\n if (refusal) errors.parentCompanyId = refusal\n }\n return Object.keys(errors).length ? { errors } : { picklists: judged.values }\n}\n\n/**\n * `POST /v1/companies`. Claimed first and released on the duplicate, the\n * ordering `createContact` argues for: a refusal that clears when the\n * duplicate is removed must not burn the key the retry will carry.\n */\nasync function createCompany(\n request: Request,\n ctx: ApiV1Context,\n): Promise<Response> {\n const body = await readJsonBody(request)\n const parsed = readCompanyInput(body, { partial: false })\n if ('errors' in parsed) return crmValidationFailed(ctx, 'company', parsed.errors)\n const site = readCrmSite(ctx, 'company', body)\n if ('response' in site) return site.response\n const owner = await memberError(ctx, 'ownerUid', parsed.values.ownerUid)\n if (Object.keys(owner).length) return crmValidationFailed(ctx, 'company', owner)\n // Judged against the org's company definitions, above the claim like\n // every other deterministic 400 (AGL-2661).\n const custom = await readCrmCustomBody(ctx, body, 'company')\n if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors)\n const customValues = custom && 'values' in custom ? custom.values : {}\n\n const collection = crmCollection(ctx, CRM_COLLECTIONS.companies)\n // The org's lists and the parent (AGL-3514), above the claim with the\n // other deterministic 400s.\n const references = await judgeCompanyReferences(\n ctx,\n collection,\n { picklists: parsed.picklists, parentCompanyId: parsed.values.parentCompanyId },\n { companyId: null, current: {} },\n )\n if ('errors' in references) return crmValidationFailed(ctx, 'company', references.errors)\n const claimed = await claimWrite(\n ctx,\n '*',\n request.headers.get('Idempotency-Key'),\n 'companies',\n )\n if ('replay' in claimed) return claimed.replay\n const { claim } = claimed\n\n try {\n const { name, domain, account, ...rest } = parsed.values\n if (domain) {\n const existing = await collection.where('domain', '==', domain).limit(1).get()\n if (!existing.empty) {\n await claim.release()\n return ApiErrors.conflict({\n message: `A company with this domain already exists (${existing.docs[0].id}). Update it instead.`,\n code: 'company_exists',\n headers: ctx.headers,\n })\n }\n }\n // The records band (AGL-2611), after the duplicate check for the reason\n // the claim ordering gives: a refusal that clears when the band is raised\n // must not burn the key the retry will carry.\n const bandFull = await crmRecordsBandRefusal(ctx)\n if (bandFull) {\n await claim.release()\n return bandFull\n }\n const id = createResourceUid()\n const record: Record<string, unknown> = {\n // `nameLower`/`nameTokens` travel with the name: the console's company\n // list searches the collection, not the page it fetched.\n ...nameSearchFields(name ?? ''),\n ...createPayload({ domain, ...rest, ...references.picklists, ...account }),\n // An empty map writes no `custom` key at all; a `null` inside one is\n // an explicit clear a fresh record has no use for.\n ...(Object.keys(customValues).length\n ? { custom: createPayload(customValues) }\n : {}),\n ...crmCreateStamp(ctx, site.siteId),\n }\n // What the console's Companies list searches and filters by (AGL-3321).\n await collection.doc(id).create({ ...record, ...crmNewRecordListFields('companies', record) })\n const view = companyView(await collection.doc(id).get())\n // Stored as 200 so a replay is distinguishable from the fresh 201.\n await claim.record(200, view)\n return apiJson(view, { status: 201, headers: ctx.headers })\n } catch (error) {\n await claim.release()\n throw error\n }\n}\n\n/** `PATCH /v1/companies/{id}` — no key, for `updateContact`'s reason. */\nasync function updateCompany(\n request: Request,\n ctx: ApiV1Context,\n ref: FirebaseFirestore.DocumentReference,\n): Promise<Response> {\n const body = await readJsonBody(request)\n const parsed = readCompanyInput(body, { partial: true })\n if ('errors' in parsed) return crmValidationFailed(ctx, 'company', parsed.errors)\n const snap = await ref.get()\n if (!snap.exists) {\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n const owner = await memberError(ctx, 'ownerUid', parsed.values.ownerUid)\n if (Object.keys(owner).length) return crmValidationFailed(ctx, 'company', owner)\n const custom = await readCrmCustomBody(ctx, body, 'company')\n if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors)\n const references = await judgeCompanyReferences(\n ctx,\n ref.parent,\n { picklists: parsed.picklists, parentCompanyId: parsed.values.parentCompanyId },\n { companyId: ref.id, current: snap.data() ?? {} },\n )\n if ('errors' in references) return crmValidationFailed(ctx, 'company', references.errors)\n\n const { name, domain, account, ...rest } = parsed.values\n if (domain && domain !== snap.get('domain')) {\n const existing = await ref.parent.where('domain', '==', domain).limit(1).get()\n if (!existing.empty && existing.docs[0].id !== ref.id) {\n return ApiErrors.conflict({\n message: `A company with this domain already exists (${existing.docs[0].id}).`,\n code: 'company_exists',\n headers: ctx.headers,\n })\n }\n }\n const update: Record<string, unknown> = {\n ...(name !== undefined ? nameSearchFields(name) : {}),\n ...updatePayload({ domain, ...rest, ...references.picklists, ...account }),\n ...(custom && 'values' in custom ? crmCustomUpdate(custom.values) : {}),\n }\n // An empty body is a no-op answered with the current company.\n if (Object.keys(update).length > 0) {\n await ref.update({ ...update, updatedAt: Timestamp.now() })\n // What the console's Companies list searches (AGL-3321) and filters\n // by (AGL-3514).\n await restampCrmListFieldsAt(ref, 'companies')\n }\n return apiJson(companyView(await ref.get()), { headers: ctx.headers })\n}\n\n/**\n * `DELETE /v1/companies/{id}` — the company alone. The deals, tasks and\n * activities filed against it keep their `companyId`; they are records of\n * their own, and a delete that cascaded through them would erase a sales\n * history because somebody removed a duplicate account. The companies\n * under it keep everything but their `parentCompanyId` (AGL-3514).\n */\nasync function deleteCompany(\n request: Request,\n ctx: ApiV1Context,\n ref: FirebaseFirestore.DocumentReference,\n): Promise<Response> {\n const claimed = await claimWrite(\n ctx,\n '*',\n request.headers.get('Idempotency-Key'),\n 'company-deletes',\n )\n if ('replay' in claimed) return claimed.replay\n const { claim } = claimed\n try {\n const snap = await ref.get()\n if (!snap.exists) {\n await claim.release()\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n // The companies under it stand on their own (AGL-3514): their parent is\n // cleared, a batch at a time, before it goes.\n for (;;) {\n const pass = await detachChildCompanies(ctx.firestore, ref.parent, ref.id)\n if (!pass.moreRemain) break\n }\n await ref.delete()\n const view = { id: ref.id, object: 'company', deleted: true }\n await claim.record(200, view)\n return apiJson(view, { headers: ctx.headers })\n } catch (error) {\n await claim.release()\n throw error\n }\n}\n\n/**\n * `GET /v1/companies` filters. `domain` is normalized exactly as the write\n * stores it, so `?domain=https://www.Example.com/about` finds `example.com`; a\n * value that is not a domain at all is a `400`, not an empty page, for the\n * reason `listContacts` gives about `?email=`.\n */\nasync function listCompanies(\n ctx: ApiV1Context,\n collection: FirebaseFirestore.CollectionReference,\n url: URL,\n): Promise<Response> {\n const rawDomain = url.searchParams.get('domain')\n const filters = readEqualityFilters(url, ['ownerUid'])\n if (rawDomain !== null && rawDomain.trim() !== '') {\n const domain = normalizeCompanyDomain(rawDomain)\n if (!domain) {\n return crmValidationFailed(ctx, 'company filter', {\n domain: 'Must be a domain name, like example.com',\n })\n }\n // The domain is unique, so it is the clause that goes to Firestore.\n filters.unshift({ field: 'domain', value: domain })\n }\n return listCrm(ctx, collection, url, filters, companyView)\n}\n\nexport async function handleCompanies(\n request: Request,\n ctx: ApiV1Context,\n segments: string[],\n url: URL,\n): Promise<Response> {\n const collection = crmCollection(ctx, CRM_COLLECTIONS.companies)\n const [, companyId] = segments\n\n if (!companyId) {\n if (request.method === 'GET') {\n const denied = requireScope(ctx, 'crm:read')\n if (denied) return denied\n return listCompanies(ctx, collection, url)\n }\n if (request.method === 'POST') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return createCompany(request, ctx)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, POST' },\n })\n }\n\n const ref = collection.doc(companyId)\n if (request.method === 'GET') {\n const denied = requireScope(ctx, 'crm:read')\n if (denied) return denied\n const snap = await ref.get()\n if (!snap.exists) {\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n return apiJson(companyView(snap), { headers: ctx.headers })\n }\n if (request.method === 'PATCH') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return updateCompany(request, ctx, ref)\n }\n if (request.method === 'DELETE') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return deleteCompany(request, ctx, ref)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, PATCH, DELETE' },\n })\n}\n"],"names":["nameSearchFields","CRM_COLLECTIONS","CRM_COMPANY_ACCOUNT_FIELDS","CRM_COMPANY_PICKLIST_FIELDS","CRM_MEDIA_IDS_MAX","createResourceUid","crmCompanyParentId","crmCompanyParentRefusal","crmNewRecordListFields","judgeCrmCompanyPicklists","normalizeAddress","normalizeCompanyDomain","normalizeCrmMediaIds","normalizePhone","readCrmCompanyAccountFields","detachChildCompanies","readCrmPicklist","apiJson","ApiErrors","restampCrmListFieldsAt","Timestamp","claimWrite","readJsonBody","requireScope","CRM_LABEL_MAX","CRM_TEXT_MAX","CRM_TITLE_MAX","createPayload","crmCollection","crmCreateStamp","crmCustomUpdate","crmCustomView","crmRecordsBandRefusal","crmTimes","crmValidationFailed","isoFromMs","listCrm","memberError","readCrmCustomBody","readCrmSite","readEqualityFilters","readOptionalText","refuseUnknownKeys","updatePayload","companyView","doc","data","id","object","name","domain","website","phone","address","industry","type","rating","ownership","accountSource","annualRevenueCents","currency","numberOfEmployees","fax","accountNumber","site","tickerSymbol","sicCode","shippingAddress","parentCompanyId","ownerUid","notes","custom","nextTaskAt","nextTaskAtMs","mediaIds","siteId","hostId","COMPANY_WRITABLE","Set","map","entry","field","readCompanyInput","body","partial","errors","values","picklists","allowed","add","undefined","String","trim","slice","Array","isArray","length","normalized","withScheme","test","parsed","URL","protocol","hostname","toString","label","account","Object","assign","includes","keys","readNamedPicklists","ctx","named","created","ids","filter","picklistId","lists","Promise","all","firestore","orgId","fromEntries","at","judgeCompanyReferences","collection","input","options","companyId","judged","current","parentId","refusal","snapshot","get","exists","createCompany","request","response","owner","customValues","companies","references","claimed","headers","replay","claim","rest","existing","where","limit","empty","release","conflict","message","docs","code","bandFull","record","create","view","status","error","updateCompany","ref","snap","notFound","parent","update","updatedAt","now","deleteCompany","pass","moreRemain","delete","deleted","listCompanies","url","rawDomain","searchParams","filters","unshift","value","handleCompanies","segments","method","denied","methodNotAllowed","Allow"],"mappings":"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"}