@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
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { CAPTURED_BY_HOST_FIELD } from "@aglyn/aglyn/app-utils/marketing-consent";
17
+ import { registerPluginRecordCountSource } from "@aglyn/aglyn/plugin-manager/plugin-record-counts";
18
+ import { collection, query, where } from "firebase/firestore";
19
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
20
+ /**
21
+ * The leads a site CAPTURED (AGL-3275), counted for another plugin's figure
22
+ * (AGL-3080). A lead is one document per person under the organization,
23
+ * stamped in `capturedByHostIds` with every site that met them — so this is
24
+ * exactly the population a site's own lead outcomes are drawn from.
25
+ *
26
+ * Not `visibleTo`: that also names the sites a consent group shares a person
27
+ * with. The price is that a collaborator scoped to one site cannot run the
28
+ * count — the rules prove a lead read by `visibleTo` — and the reader
29
+ * withholds the figure for them.
30
+ */ export const leadRecordCountSource = {
31
+ query (firestore, request) {
32
+ if (!request.orgId || !request.hostId) return null;
33
+ return query(collection(firestore, 'orgs', request.orgId, 'leads'), where(CAPTURED_BY_HOST_FIELD, 'array-contains', request.hostId));
34
+ }
35
+ };
36
+ /**
37
+ * The organization's contacts — ONE row per person for every site in it, so
38
+ * the count crosses sites, which the reader is told.
39
+ */ export const contactRecordCountSource = {
40
+ query (firestore, request) {
41
+ return request.orgId ? collection(firestore, 'orgs', request.orgId, 'contacts') : null;
42
+ },
43
+ crossesSites: true
44
+ };
45
+ /** Called from the console registrar, owner named for a spec that calls it directly. */ export function registerCrmRecordCounts() {
46
+ registerPluginRecordCountSource('lead', leadRecordCountSource, {
47
+ pluginId: BUNDLE_ID
48
+ });
49
+ registerPluginRecordCountSource('contact', contactRecordCountSource, {
50
+ pluginId: BUNDLE_ID
51
+ });
52
+ }
53
+
54
+ //# sourceMappingURL=crm-record-counts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/model/crm-record-counts.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\nimport { CAPTURED_BY_HOST_FIELD } from '@aglyn/aglyn/app-utils/marketing-consent'\nimport {\n registerPluginRecordCountSource,\n type PluginRecordCountSource,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-counts'\nimport { collection, query, where } from 'firebase/firestore'\nimport { BUNDLE_ID } from '../constants/bundle-common'\n\n/**\n * The leads a site CAPTURED (AGL-3275), counted for another plugin's figure\n * (AGL-3080). A lead is one document per person under the organization,\n * stamped in `capturedByHostIds` with every site that met them — so this is\n * exactly the population a site's own lead outcomes are drawn from.\n *\n * Not `visibleTo`: that also names the sites a consent group shares a person\n * with. The price is that a collaborator scoped to one site cannot run the\n * count — the rules prove a lead read by `visibleTo` — and the reader\n * withholds the figure for them.\n */\nexport const leadRecordCountSource: PluginRecordCountSource = {\n query(firestore, request) {\n if (!request.orgId || !request.hostId) return null\n return query(\n collection(firestore, 'orgs', request.orgId, 'leads'),\n where(CAPTURED_BY_HOST_FIELD, 'array-contains', request.hostId),\n )\n },\n}\n\n/**\n * The organization's contacts — ONE row per person for every site in it, so\n * the count crosses sites, which the reader is told.\n */\nexport const contactRecordCountSource: PluginRecordCountSource = {\n query(firestore, request) {\n return request.orgId ? collection(firestore, 'orgs', request.orgId, 'contacts') : null\n },\n crossesSites: true,\n}\n\n/** Called from the console registrar, owner named for a spec that calls it directly. */\nexport function registerCrmRecordCounts(): void {\n registerPluginRecordCountSource('lead', leadRecordCountSource, { pluginId: BUNDLE_ID })\n registerPluginRecordCountSource('contact', contactRecordCountSource, { pluginId: BUNDLE_ID })\n}\n"],"names":["CAPTURED_BY_HOST_FIELD","registerPluginRecordCountSource","collection","query","where","BUNDLE_ID","leadRecordCountSource","firestore","request","orgId","hostId","contactRecordCountSource","crossesSites","registerCrmRecordCounts","pluginId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,sBAAsB,QAAQ,2CAA0C;AACjF,SACEC,+BAA+B,QAE1B,mDAAkD;AACzD,SAASC,UAAU,EAAEC,KAAK,EAAEC,KAAK,QAAQ,qBAAoB;AAC7D,SAASC,SAAS,QAAQ,gCAA4B;AAEtD;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,wBAAiD;IAC5DH,OAAMI,SAAS,EAAEC,OAAO;QACtB,IAAI,CAACA,QAAQC,KAAK,IAAI,CAACD,QAAQE,MAAM,EAAE,OAAO;QAC9C,OAAOP,MACLD,WAAWK,WAAW,QAAQC,QAAQC,KAAK,EAAE,UAC7CL,MAAMJ,wBAAwB,kBAAkBQ,QAAQE,MAAM;IAElE;AACF,EAAC;AAED;;;CAGC,GACD,OAAO,MAAMC,2BAAoD;IAC/DR,OAAMI,SAAS,EAAEC,OAAO;QACtB,OAAOA,QAAQC,KAAK,GAAGP,WAAWK,WAAW,QAAQC,QAAQC,KAAK,EAAE,cAAc;IACpF;IACAG,cAAc;AAChB,EAAC;AAED,sFAAsF,GACtF,OAAO,SAASC;IACdZ,gCAAgC,QAAQK,uBAAuB;QAAEQ,UAAUT;IAAU;IACrFJ,gCAAgC,WAAWU,0BAA0B;QAAEG,UAAUT;IAAU;AAC7F"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type PluginRecordListSource } from '@aglyn/aglyn/plugin-manager/plugin-record-lists';
18
+ export declare const savedViewRecordListSource: PluginRecordListSource;
19
+ export declare const messageTemplateRecordListSource: PluginRecordListSource;
20
+ export declare const contactRecordListSource: PluginRecordListSource;
21
+ export declare const leadRecordListSource: PluginRecordListSource;
22
+ /** Called from the console registrar, owner named for a spec that calls it directly. */
23
+ export declare function registerCrmRecordLists(): void;
@@ -0,0 +1,161 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { contactDisplayName, normalizeContactEmail } from "@aglyn/aglyn/app-utils/contacts";
17
+ import { CRM_COLLECTIONS, crmLeadDisplayName, crmViewIsListed, isCrmLeadOpen, normalizeCrmViewFilters } from "@aglyn/aglyn/app-utils/crm";
18
+ import { CRM_EMAIL_TEMPLATES_LIMIT, crmEmailTemplateIsListed, normalizeCrmEmailTemplate } from "@aglyn/aglyn/app-utils/crm-email-templates";
19
+ import { dynamicListDimensionsForCrmView } from "@aglyn/aglyn/app-utils/dynamic-list-rule";
20
+ import { nameSearchToken } from "@aglyn/aglyn/app-utils/name-search";
21
+ import { scopeTokensForHost, visibleToHost } from "@aglyn/aglyn/app-utils/scope-tokens";
22
+ import { registerPluginRecordListSource } from "@aglyn/aglyn/plugin-manager/plugin-record-lists";
23
+ import { collection, limit, orderBy, query, where } from "firebase/firestore";
24
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
25
+ /**
26
+ * The CRM's records, FOUND in the console for another plugin's picker
27
+ * (AGL-3080) — a sales sequence choosing whom to enroll and what to send —
28
+ * through `plugin-record-lists`, so the reader never learns where the CRM
29
+ * keeps any of it or which rule its security rules hold a query to.
30
+ *
31
+ * Four kinds, each org-scoped (`orgId` required) and each the query the
32
+ * CRM's own console reads the same records by:
33
+ *
34
+ * `savedView` — the saved views of the Contacts and Leads lists this member
35
+ * may list: their own and the shared ones. Facts:
36
+ * `{ recordKind: 'contact' | 'lead', takeable: boolean }`. `takeable` is
37
+ * whether the view can be taken whole as an audience: a Leads view narrows by
38
+ * status alone, which is always applied; a Contacts view filtering on
39
+ * something only the list itself can apply is not, because dropping that
40
+ * filter would take more people than the view shows.
41
+ *
42
+ * `messageTemplate` — the email templates and snippets this member may list,
43
+ * written for the whole organization or for the named site. Facts:
44
+ * `{ kind: 'template' | 'snippet', subject, body }`.
45
+ *
46
+ * `contact` — a SEARCH of the site's contacts: by address when the text is
47
+ * one, otherwise by a word of the name. None with nothing typed. Named as the
48
+ * site's consent group knows them. Facts: `{ email }`.
49
+ *
50
+ * `lead` — the site's most recently seen leads, newest first. Facts:
51
+ * `{ email, open }`, `open` being a lead nobody has closed or converted.
52
+ */ const named = (value)=>typeof value === 'string' ? value.trim() : '';
53
+ export const savedViewRecordListSource = {
54
+ query (firestore, request) {
55
+ if (!request.orgId) return null;
56
+ return query(collection(firestore, 'orgs', request.orgId, CRM_COLLECTIONS.views), where('section', 'in', [
57
+ 'contacts',
58
+ 'leads'
59
+ ]), orderBy('name'), limit(request.limit));
60
+ },
61
+ record (id, data, request) {
62
+ var _data_ownerUid, _ref;
63
+ const name = named(data['name']);
64
+ if (!name) return null;
65
+ // A colleague's private view is theirs.
66
+ if (!crmViewIsListed({
67
+ shared: data['shared'] === true,
68
+ ownerUid: String((_data_ownerUid = data['ownerUid']) != null ? _data_ownerUid : '')
69
+ }, (_ref = request == null ? void 0 : request.viewerUid) != null ? _ref : null)) {
70
+ return null;
71
+ }
72
+ const leads = data['section'] === 'leads';
73
+ const takeable = leads || dynamicListDimensionsForCrmView(normalizeCrmViewFilters(data['filters'])).unsupported.length === 0;
74
+ return {
75
+ id,
76
+ name,
77
+ facts: {
78
+ recordKind: leads ? 'lead' : 'contact',
79
+ takeable
80
+ }
81
+ };
82
+ }
83
+ };
84
+ export const messageTemplateRecordListSource = {
85
+ query (firestore, request) {
86
+ if (!request.orgId) return null;
87
+ return query(collection(firestore, 'orgs', request.orgId, CRM_COLLECTIONS.emailTemplates), orderBy('name'), limit(Math.min(request.limit, CRM_EMAIL_TEMPLATES_LIMIT)));
88
+ },
89
+ record (id, data, request) {
90
+ var _ref;
91
+ const template = normalizeCrmEmailTemplate(data);
92
+ if (!template.name) return null;
93
+ // The team's and this member's own, written for the organization or the site.
94
+ if (!crmEmailTemplateIsListed(template, (_ref = request == null ? void 0 : request.viewerUid) != null ? _ref : null)) return null;
95
+ if ((request == null ? void 0 : request.hostId) && !visibleToHost(template.visibleTo, request.hostId)) return null;
96
+ return {
97
+ id,
98
+ name: template.name,
99
+ facts: {
100
+ kind: template.kind,
101
+ subject: template.subject,
102
+ body: template.body
103
+ }
104
+ };
105
+ }
106
+ };
107
+ export const contactRecordListSource = {
108
+ query (firestore, request) {
109
+ if (!request.orgId || !request.hostId) return null;
110
+ const email = normalizeContactEmail(request.search);
111
+ const token = email ? '' : nameSearchToken(request.search);
112
+ if (!email && !token) return null;
113
+ const contacts = collection(firestore, 'orgs', request.orgId, 'contacts');
114
+ return email ? query(contacts, where('email', '==', email), limit(request.limit)) : query(contacts, where('nameTokens', 'array-contains', token), orderBy('nameLower'), limit(request.limit));
115
+ },
116
+ record (id, data, request) {
117
+ const hostId = request == null ? void 0 : request.hostId;
118
+ if (hostId && !visibleToHost(data['visibleTo'], hostId)) return null;
119
+ const email = normalizeContactEmail(data['email']);
120
+ const name = contactDisplayName(data, (request == null ? void 0 : request.consentGroupId) || hostId || '').trim() || email || '';
121
+ if (!name) return null;
122
+ return {
123
+ id,
124
+ name,
125
+ facts: {
126
+ email
127
+ }
128
+ };
129
+ }
130
+ };
131
+ export const leadRecordListSource = {
132
+ query (firestore, request) {
133
+ if (!request.orgId || !request.hostId) return null;
134
+ // The org collection, narrowed to the site (AGL-3275) — unscoped it would
135
+ // offer one agency client another client's people.
136
+ return query(collection(firestore, 'orgs', request.orgId, 'leads'), where('visibleTo', 'array-contains-any', scopeTokensForHost(request.hostId)), orderBy('lastSeenAtMs', 'desc'), limit(request.limit));
137
+ },
138
+ record (id, data) {
139
+ const name = crmLeadDisplayName(data);
140
+ if (!name) return null;
141
+ return {
142
+ id,
143
+ name,
144
+ facts: {
145
+ email: normalizeContactEmail(data['email']),
146
+ open: isCrmLeadOpen(data) && !data['convertedContactId']
147
+ }
148
+ };
149
+ }
150
+ };
151
+ /** Called from the console registrar, owner named for a spec that calls it directly. */ export function registerCrmRecordLists() {
152
+ const owner = {
153
+ pluginId: BUNDLE_ID
154
+ };
155
+ registerPluginRecordListSource('savedView', savedViewRecordListSource, owner);
156
+ registerPluginRecordListSource('messageTemplate', messageTemplateRecordListSource, owner);
157
+ registerPluginRecordListSource('contact', contactRecordListSource, owner);
158
+ registerPluginRecordListSource('lead', leadRecordListSource, owner);
159
+ }
160
+
161
+ //# sourceMappingURL=crm-record-lists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/model/crm-record-lists.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\nimport { contactDisplayName, normalizeContactEmail } from '@aglyn/aglyn/app-utils/contacts'\nimport {\n CRM_COLLECTIONS,\n crmLeadDisplayName,\n crmViewIsListed,\n isCrmLeadOpen,\n normalizeCrmViewFilters,\n} from '@aglyn/aglyn/app-utils/crm'\nimport {\n CRM_EMAIL_TEMPLATES_LIMIT,\n crmEmailTemplateIsListed,\n normalizeCrmEmailTemplate,\n} from '@aglyn/aglyn/app-utils/crm-email-templates'\nimport { dynamicListDimensionsForCrmView } from '@aglyn/aglyn/app-utils/dynamic-list-rule'\nimport { nameSearchToken } from '@aglyn/aglyn/app-utils/name-search'\nimport { scopeTokensForHost, visibleToHost } from '@aglyn/aglyn/app-utils/scope-tokens'\nimport {\n registerPluginRecordListSource,\n type PluginRecordListSource,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-lists'\nimport { collection, limit, orderBy, query, where } from 'firebase/firestore'\nimport { BUNDLE_ID } from '../constants/bundle-common'\n\n/**\n * The CRM's records, FOUND in the console for another plugin's picker\n * (AGL-3080) — a sales sequence choosing whom to enroll and what to send —\n * through `plugin-record-lists`, so the reader never learns where the CRM\n * keeps any of it or which rule its security rules hold a query to.\n *\n * Four kinds, each org-scoped (`orgId` required) and each the query the\n * CRM's own console reads the same records by:\n *\n * `savedView` — the saved views of the Contacts and Leads lists this member\n * may list: their own and the shared ones. Facts:\n * `{ recordKind: 'contact' | 'lead', takeable: boolean }`. `takeable` is\n * whether the view can be taken whole as an audience: a Leads view narrows by\n * status alone, which is always applied; a Contacts view filtering on\n * something only the list itself can apply is not, because dropping that\n * filter would take more people than the view shows.\n *\n * `messageTemplate` — the email templates and snippets this member may list,\n * written for the whole organization or for the named site. Facts:\n * `{ kind: 'template' | 'snippet', subject, body }`.\n *\n * `contact` — a SEARCH of the site's contacts: by address when the text is\n * one, otherwise by a word of the name. None with nothing typed. Named as the\n * site's consent group knows them. Facts: `{ email }`.\n *\n * `lead` — the site's most recently seen leads, newest first. Facts:\n * `{ email, open }`, `open` being a lead nobody has closed or converted.\n */\n\nconst named = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\nexport const savedViewRecordListSource: PluginRecordListSource = {\n query(firestore, request) {\n if (!request.orgId) return null\n return query(\n collection(firestore, 'orgs', request.orgId, CRM_COLLECTIONS.views),\n where('section', 'in', ['contacts', 'leads']),\n orderBy('name'),\n limit(request.limit),\n )\n },\n record(id, data, request) {\n const name = named(data['name'])\n if (!name) return null\n // A colleague's private view is theirs.\n if (\n !crmViewIsListed(\n { shared: data['shared'] === true, ownerUid: String(data['ownerUid'] ?? '') },\n request?.viewerUid ?? null,\n )\n ) {\n return null\n }\n const leads = data['section'] === 'leads'\n const takeable =\n leads || dynamicListDimensionsForCrmView(normalizeCrmViewFilters(data['filters'])).unsupported.length === 0\n return { id, name, facts: { recordKind: leads ? 'lead' : 'contact', takeable } }\n },\n}\n\nexport const messageTemplateRecordListSource: PluginRecordListSource = {\n query(firestore, request) {\n if (!request.orgId) return null\n return query(\n collection(firestore, 'orgs', request.orgId, CRM_COLLECTIONS.emailTemplates),\n orderBy('name'),\n limit(Math.min(request.limit, CRM_EMAIL_TEMPLATES_LIMIT)),\n )\n },\n record(id, data, request) {\n const template = normalizeCrmEmailTemplate(data)\n if (!template.name) return null\n // The team's and this member's own, written for the organization or the site.\n if (!crmEmailTemplateIsListed(template, request?.viewerUid ?? null)) return null\n if (request?.hostId && !visibleToHost(template.visibleTo, request.hostId)) return null\n return {\n id,\n name: template.name,\n facts: { kind: template.kind, subject: template.subject, body: template.body },\n }\n },\n}\n\nexport const contactRecordListSource: PluginRecordListSource = {\n query(firestore, request) {\n if (!request.orgId || !request.hostId) return null\n const email = normalizeContactEmail(request.search)\n const token = email ? '' : nameSearchToken(request.search)\n if (!email && !token) return null\n const contacts = collection(firestore, 'orgs', request.orgId, 'contacts')\n return email\n ? query(contacts, where('email', '==', email), limit(request.limit))\n : query(contacts, where('nameTokens', 'array-contains', token), orderBy('nameLower'), limit(request.limit))\n },\n record(id, data, request) {\n const hostId = request?.hostId\n if (hostId && !visibleToHost(data['visibleTo'] as string[] | undefined, hostId)) return null\n const email = normalizeContactEmail(data['email'])\n const name = contactDisplayName(data, request?.consentGroupId || hostId || '').trim() || email || ''\n if (!name) return null\n return { id, name, facts: { email } }\n },\n}\n\nexport const leadRecordListSource: PluginRecordListSource = {\n query(firestore, request) {\n if (!request.orgId || !request.hostId) return null\n // The org collection, narrowed to the site (AGL-3275) — unscoped it would\n // offer one agency client another client's people.\n return query(\n collection(firestore, 'orgs', request.orgId, 'leads'),\n where('visibleTo', 'array-contains-any', scopeTokensForHost(request.hostId)),\n orderBy('lastSeenAtMs', 'desc'),\n limit(request.limit),\n )\n },\n record(id, data) {\n const name = crmLeadDisplayName(data)\n if (!name) return null\n return {\n id,\n name,\n facts: {\n email: normalizeContactEmail(data['email']),\n open: isCrmLeadOpen(data as never) && !data['convertedContactId'],\n },\n }\n },\n}\n\n/** Called from the console registrar, owner named for a spec that calls it directly. */\nexport function registerCrmRecordLists(): void {\n const owner = { pluginId: BUNDLE_ID }\n registerPluginRecordListSource('savedView', savedViewRecordListSource, owner)\n registerPluginRecordListSource('messageTemplate', messageTemplateRecordListSource, owner)\n registerPluginRecordListSource('contact', contactRecordListSource, owner)\n registerPluginRecordListSource('lead', leadRecordListSource, owner)\n}\n"],"names":["contactDisplayName","normalizeContactEmail","CRM_COLLECTIONS","crmLeadDisplayName","crmViewIsListed","isCrmLeadOpen","normalizeCrmViewFilters","CRM_EMAIL_TEMPLATES_LIMIT","crmEmailTemplateIsListed","normalizeCrmEmailTemplate","dynamicListDimensionsForCrmView","nameSearchToken","scopeTokensForHost","visibleToHost","registerPluginRecordListSource","collection","limit","orderBy","query","where","BUNDLE_ID","named","value","trim","savedViewRecordListSource","firestore","request","orgId","views","record","id","data","name","shared","ownerUid","String","viewerUid","leads","takeable","unsupported","length","facts","recordKind","messageTemplateRecordListSource","emailTemplates","Math","min","template","hostId","visibleTo","kind","subject","body","contactRecordListSource","email","search","token","contacts","consentGroupId","leadRecordListSource","open","registerCrmRecordLists","owner","pluginId"],"mappings":"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"}
@@ -30,7 +30,8 @@
30
30
  * needs "now" is handed it.
31
31
  */
32
32
  import type { ContactFacet, ContactSource } from '@aglyn/aglyn/app-utils/contacts';
33
- import { type ContactLifecycleStage, type CrmActivity, type CrmActivityKind, type CrmDeal, type CrmDealStage, type CrmLeadFields, type CrmLeadStatus, type CrmPipeline, type CrmTask } from '@aglyn/aglyn/app-utils/crm';
33
+ import { type ContactLifecycleStage, type CrmActivity, type CrmActivityKind, type CrmDeal, type CrmDealStage, type CrmLeadFields, type CrmLeadStatus, type CrmPicklist, type CrmPipeline, type CrmTask } from '@aglyn/aglyn/app-utils/crm';
34
+ import { type LeadSourceDirection } from './lead-source-direction';
34
35
  /**
35
36
  * The periods a report can be read over.
36
37
  *
@@ -161,7 +162,7 @@ export interface PipelineTotals {
161
162
  amountCents: number;
162
163
  };
163
164
  }
164
- type PipelineDeal = Pick<CrmDeal, 'status' | 'stageId' | 'amountCents'>;
165
+ type PipelineDeal = Pick<CrmDeal, 'status' | 'stageId' | 'amountCents'> & Partial<Pick<CrmDeal, 'probability'>>;
165
166
  /**
166
167
  * What a pipeline holds, by stage.
167
168
  *
@@ -223,7 +224,7 @@ export interface CloseMonthForecast {
223
224
  later: ForecastCell;
224
225
  total: ForecastCell;
225
226
  }
226
- type ForecastDeal = Pick<CrmDeal, 'status' | 'pipelineId' | 'stageId' | 'amountCents' | 'expectedCloseAtMs'>;
227
+ type ForecastDeal = Pick<CrmDeal, 'status' | 'pipelineId' | 'stageId' | 'amountCents' | 'expectedCloseAtMs'> & Partial<Pick<CrmDeal, 'probability' | 'forecastCategory'>>;
227
228
  /**
228
229
  * The open pipeline laid out by the month each deal is expected to close
229
230
  * (AGL-2620): per pipeline, one cell per month for the next
@@ -247,6 +248,32 @@ type ForecastDeal = Pick<CrmDeal, 'status' | 'pipelineId' | 'stageId' | 'amountC
247
248
  export declare function forecastByCloseMonth(deals: readonly ForecastDeal[], pipelines: ReadonlyArray<Pick<CrmPipeline, 'name' | 'stages' | 'archivedAt'> & {
248
249
  $id: string;
249
250
  }>, nowMs: number, months?: number): CloseMonthForecast;
251
+ /**
252
+ * The rows of the forecast by category (AGL-3516), in the order Salesforce's
253
+ * forecast reads them: what is still in play from least to most certain,
254
+ * then what has closed. Omitted is not a forecast row — a deal put there
255
+ * is one the team chose to leave out — and is reported beside it.
256
+ */
257
+ export declare const FORECAST_CATEGORY_ROWS: readonly ["pipeline", "bestCase", "commit", "closed"];
258
+ export interface CategoryForecast {
259
+ /** One cell per {@link FORECAST_CATEGORY_ROWS} entry, every one present. */
260
+ rows: Record<(typeof FORECAST_CATEGORY_ROWS)[number], ForecastCell>;
261
+ /** Open deals left out of the forecast on purpose. */
262
+ omitted: ForecastCell;
263
+ /** Every row added up — what the forecast forecasts. */
264
+ total: ForecastCell;
265
+ }
266
+ /**
267
+ * The forecast by category (AGL-3516): the OPEN deals by the category each
268
+ * stands in — its own, else its stage's ({@link dealForecastCategory}) —
269
+ * weighted as everywhere else, and the WON deals the caller read as
270
+ * Closed, at full value because they have closed. An open deal somebody
271
+ * put in Closed joins that row at its weighted value — it is still open,
272
+ * so it is not counted as revenue. A lost deal is never a forecast.
273
+ */
274
+ export declare function forecastByCategory(openDeals: readonly ForecastDeal[], wonDeals: ReadonlyArray<Pick<CrmDeal, 'status' | 'amountCents'>>, pipelines: ReadonlyArray<Pick<CrmPipeline, 'stages'> & {
275
+ $id: string;
276
+ }>): CategoryForecast;
250
277
  /**
251
278
  * How many of a list share each key, most common first.
252
279
  *
@@ -464,4 +491,47 @@ export interface OwnerOutcomeRow {
464
491
  * the uid, so two renders of one window draw one order.
465
492
  */
466
493
  export declare function wonLostByOwner(won: readonly OwnerOutcomeDeal[], lost: readonly OwnerOutcomeDeal[]): OwnerOutcomeRow[];
494
+ /** A lead as the lead source tally reads it. */
495
+ type LeadSourceLead = Pick<CrmLeadFields, 'status' | 'leadSource'>;
496
+ /** The key a lead with no lead source is tallied under. */
497
+ export declare const LEAD_SOURCE_NONE_KEY = "";
498
+ export interface LeadSourceRow {
499
+ /** The label as the org's list spells it, as the lead holds it when unlisted, `''` for none. */
500
+ label: string;
501
+ /** The value's group in the org's list; `null` for none, an ungrouped value or an unlisted one. */
502
+ direction: LeadSourceDirection | null;
503
+ /** Whether the org's list holds the value at all. */
504
+ listed: boolean;
505
+ leads: number;
506
+ /** Of those, the ones qualified — converted to a contact. */
507
+ qualified: number;
508
+ /** `qualified / leads`, 0–1. */
509
+ rate: number;
510
+ }
511
+ export interface LeadSourceDirectionRow {
512
+ /** `null` is Unspecified: no lead source, or one in no group. */
513
+ direction: LeadSourceDirection | null;
514
+ leads: number;
515
+ qualified: number;
516
+ rate: number;
517
+ }
518
+ export interface LeadSourceBreakdown {
519
+ /** One row per value any lead holds, in the order the org keeps its list; unlisted after, none last. */
520
+ rows: LeadSourceRow[];
521
+ /** Inbound, Outbound and Unspecified, each present even at zero. */
522
+ directions: LeadSourceDirectionRow[];
523
+ total: number;
524
+ qualified: number;
525
+ }
526
+ /**
527
+ * The period's leads by their lead source, and by the direction each
528
+ * source's group gives it.
529
+ *
530
+ * Grouped through the org's EFFECTIVE list as it stands now: two spellings
531
+ * of one value are one row, a value is listed under the group it is in
532
+ * today, and a label the list no longer holds stays a row of its own rather
533
+ * than being folded into another. Qualified is the conversion the Lead
534
+ * funnel counts — a lead the conversion closed as a contact.
535
+ */
536
+ export declare function leadsByLeadSource(leads: readonly LeadSourceLead[], picklist: CrmPicklist): LeadSourceBreakdown;
467
537
  export {};
@@ -28,7 +28,8 @@
28
28
  * Pure data module: no Firestore, no React, no clock — every function that
29
29
  * needs "now" is handed it.
30
30
  */ import { _ as _extends } from "@swc/helpers/_/_extends";
31
- import { CONTACT_LIFECYCLE_STAGES, CONTACT_LIFECYCLE_STAGE_LABELS, CRM_ACTIVITY_KINDS, CRM_LEAD_STATUSES, crmLeadStatus, dealStageById, isCrmActivityKind, isPipelineArchived, weightedDealAmountCents } from "@aglyn/aglyn/app-utils/crm";
31
+ import { CONTACT_LIFECYCLE_STAGES, CONTACT_LIFECYCLE_STAGE_LABELS, CRM_ACTIVITY_KINDS, CRM_LEAD_STATUSES, crmLeadStatus, crmPicklistRank, crmPicklistValueByLabel, dealForecastCategory, dealStageById, isCrmActivityKind, isPipelineArchived, weightedDealAmountCents } from "@aglyn/aglyn/app-utils/crm";
32
+ import { leadSourceDirectionOf } from "./lead-source-direction.js";
32
33
  const DAY_MS = 24 * 60 * 60 * 1000;
33
34
  const WEEK_MS = 7 * DAY_MS;
34
35
  /**
@@ -360,6 +361,59 @@ function addToCell(cell, amountCents, weightedCents) {
360
361
  ];
361
362
  return totals;
362
363
  }
364
+ /**
365
+ * The rows of the forecast by category (AGL-3516), in the order Salesforce's
366
+ * forecast reads them: what is still in play from least to most certain,
367
+ * then what has closed. Omitted is not a forecast row — a deal put there
368
+ * is one the team chose to leave out — and is reported beside it.
369
+ */ export const FORECAST_CATEGORY_ROWS = [
370
+ 'pipeline',
371
+ 'bestCase',
372
+ 'commit',
373
+ 'closed'
374
+ ];
375
+ /**
376
+ * The forecast by category (AGL-3516): the OPEN deals by the category each
377
+ * stands in — its own, else its stage's ({@link dealForecastCategory}) —
378
+ * weighted as everywhere else, and the WON deals the caller read as
379
+ * Closed, at full value because they have closed. An open deal somebody
380
+ * put in Closed joins that row at its weighted value — it is still open,
381
+ * so it is not counted as revenue. A lost deal is never a forecast.
382
+ */ export function forecastByCategory(openDeals, wonDeals, pipelines) {
383
+ const forecast = {
384
+ rows: {
385
+ pipeline: emptyCell(),
386
+ bestCase: emptyCell(),
387
+ commit: emptyCell(),
388
+ closed: emptyCell()
389
+ },
390
+ omitted: emptyCell(),
391
+ total: emptyCell()
392
+ };
393
+ for (const deal of openDeals){
394
+ var _deal_amountCents;
395
+ if (deal.status !== 'open') continue;
396
+ const pipeline = pipelines.find((entry)=>entry.$id === deal.pipelineId);
397
+ const stage = dealStageById(pipeline, deal.stageId);
398
+ const amount = Math.max(0, Math.round(Number((_deal_amountCents = deal.amountCents) != null ? _deal_amountCents : 0) || 0));
399
+ const weighted = weightedDealAmountCents(deal, stage);
400
+ const category = dealForecastCategory(deal, stage);
401
+ if (category === 'omitted') {
402
+ addToCell(forecast.omitted, amount, weighted);
403
+ continue;
404
+ }
405
+ addToCell(forecast.rows[category], amount, weighted);
406
+ addToCell(forecast.total, amount, weighted);
407
+ }
408
+ for (const deal of wonDeals){
409
+ var _deal_amountCents1;
410
+ if (deal.status !== 'won') continue;
411
+ const amount = Math.max(0, Math.round(Number((_deal_amountCents1 = deal.amountCents) != null ? _deal_amountCents1 : 0) || 0));
412
+ addToCell(forecast.rows.closed, amount, amount);
413
+ addToCell(forecast.total, amount, amount);
414
+ }
415
+ return forecast;
416
+ }
363
417
  /**
364
418
  * How many of a list share each key, most common first.
365
419
  *
@@ -663,5 +717,70 @@ export const LEAD_NO_REASON_LABEL = 'No reason given';
663
717
  winRate: row.closed ? row.won / row.closed : null
664
718
  })).sort((a, b)=>b.closed - a.closed || b.won - a.won || a.uid.localeCompare(b.uid));
665
719
  }
720
+ /** The key a lead with no lead source is tallied under. */ export const LEAD_SOURCE_NONE_KEY = '';
721
+ /**
722
+ * The period's leads by their lead source, and by the direction each
723
+ * source's group gives it.
724
+ *
725
+ * Grouped through the org's EFFECTIVE list as it stands now: two spellings
726
+ * of one value are one row, a value is listed under the group it is in
727
+ * today, and a label the list no longer holds stays a row of its own rather
728
+ * than being folded into another. Qualified is the conversion the Lead
729
+ * funnel counts — a lead the conversion closed as a contact.
730
+ */ export function leadsByLeadSource(leads, picklist) {
731
+ const rows = new Map();
732
+ const directions = new Map([
733
+ 'inbound',
734
+ 'outbound',
735
+ null
736
+ ].map((direction)=>[
737
+ direction,
738
+ {
739
+ direction,
740
+ leads: 0,
741
+ qualified: 0,
742
+ rate: 0
743
+ }
744
+ ]));
745
+ let qualified = 0;
746
+ for (const lead of leads){
747
+ var _lead_leadSource, _ref, _rows_get;
748
+ const isQualified = crmLeadStatus(lead) === 'qualified';
749
+ if (isQualified) qualified += 1;
750
+ const held = String((_lead_leadSource = lead.leadSource) != null ? _lead_leadSource : '').replace(/\s+/g, ' ').trim();
751
+ const value = held ? crmPicklistValueByLabel(picklist, held) : null;
752
+ const label = (_ref = value == null ? void 0 : value.label) != null ? _ref : held;
753
+ const key = label.toLowerCase();
754
+ const direction = held ? leadSourceDirectionOf(picklist, held) : null;
755
+ const row = (_rows_get = rows.get(key)) != null ? _rows_get : {
756
+ label,
757
+ direction,
758
+ listed: Boolean(value),
759
+ leads: 0,
760
+ qualified: 0,
761
+ rate: 0
762
+ };
763
+ row.leads += 1;
764
+ if (isQualified) row.qualified += 1;
765
+ rows.set(key, row);
766
+ const tally = directions.get(direction);
767
+ tally.leads += 1;
768
+ if (isQualified) tally.qualified += 1;
769
+ }
770
+ const rate = (row)=>_extends({}, row, {
771
+ rate: row.leads > 0 ? row.qualified / row.leads : 0
772
+ });
773
+ const rank = (row)=>row.label === LEAD_SOURCE_NONE_KEY ? Number.MAX_SAFE_INTEGER : crmPicklistRank(picklist, row.label);
774
+ return {
775
+ rows: [
776
+ ...rows.values()
777
+ ].map(rate).sort((a, b)=>rank(a) - rank(b) || a.label.localeCompare(b.label)),
778
+ directions: [
779
+ ...directions.values()
780
+ ].map(rate),
781
+ total: leads.length,
782
+ qualified
783
+ };
784
+ }
666
785
 
667
786
  //# sourceMappingURL=crm-reports.js.map