@aglyn/plugins-crm 1.0.0-beta.220 → 1.0.0-beta.222
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.
- package/README.md +2 -1
- package/package.json +13 -13
- package/src/lib/components/activity-list.js +12 -5
- package/src/lib/components/activity-list.js.map +1 -1
- package/src/lib/components/companies-bulk-bar.d.ts +1 -4
- package/src/lib/components/companies-bulk-bar.js +7 -20
- package/src/lib/components/companies-bulk-bar.js.map +1 -1
- package/src/lib/components/companies-section.d.ts +3 -3
- package/src/lib/components/companies-section.js +149 -46
- package/src/lib/components/companies-section.js.map +1 -1
- package/src/lib/components/company-edit-drawer.js +281 -20
- package/src/lib/components/company-edit-drawer.js.map +1 -1
- package/src/lib/components/company-properties-card.js +99 -8
- package/src/lib/components/company-properties-card.js.map +1 -1
- package/src/lib/components/contact-detail-page.js +3 -1
- package/src/lib/components/contact-detail-page.js.map +1 -1
- package/src/lib/components/contact-merge-dialog.js +33 -10
- package/src/lib/components/contact-merge-dialog.js.map +1 -1
- package/src/lib/components/contact-properties-card.d.ts +0 -69
- package/src/lib/components/contact-properties-card.js +350 -60
- package/src/lib/components/contact-properties-card.js.map +1 -1
- package/src/lib/components/contact-reports-to-field.d.ts +46 -0
- package/src/lib/components/contact-reports-to-field.js +67 -0
- package/src/lib/components/contact-reports-to-field.js.map +1 -0
- package/src/lib/components/contacts-bulk-bar.d.ts +1 -8
- package/src/lib/components/contacts-bulk-bar.js +7 -19
- package/src/lib/components/contacts-bulk-bar.js.map +1 -1
- package/src/lib/components/contacts-section.js +46 -33
- package/src/lib/components/contacts-section.js.map +1 -1
- package/src/lib/components/crm-call-actions.d.ts +10 -0
- package/src/lib/components/crm-call-actions.js +26 -9
- package/src/lib/components/crm-call-actions.js.map +1 -1
- package/src/lib/components/crm-record-picker.d.ts +15 -0
- package/src/lib/components/crm-record-picker.js +16 -10
- package/src/lib/components/crm-record-picker.js.map +1 -1
- package/src/lib/components/crm-transfer-buttons.d.ts +54 -0
- package/src/lib/components/crm-transfer-buttons.js +167 -0
- package/src/lib/components/crm-transfer-buttons.js.map +1 -0
- package/src/lib/components/deal-contact-roles-card.d.ts +46 -0
- package/src/lib/components/deal-contact-roles-card.js +368 -0
- package/src/lib/components/deal-contact-roles-card.js.map +1 -0
- package/src/lib/components/deal-detail-page.d.ts +3 -2
- package/src/lib/components/deal-detail-page.js +25 -6
- package/src/lib/components/deal-detail-page.js.map +1 -1
- package/src/lib/components/deal-edit-drawer.d.ts +10 -0
- package/src/lib/components/deal-edit-drawer.js +219 -10
- package/src/lib/components/deal-edit-drawer.js.map +1 -1
- package/src/lib/components/deal-properties-card.d.ts +7 -0
- package/src/lib/components/deal-properties-card.js +34 -3
- package/src/lib/components/deal-properties-card.js.map +1 -1
- package/src/lib/components/deal-stage-card.d.ts +4 -0
- package/src/lib/components/deal-stage-card.js +10 -2
- package/src/lib/components/deal-stage-card.js.map +1 -1
- package/src/lib/components/deals-bulk-bar.d.ts +0 -3
- package/src/lib/components/deals-bulk-bar.js +7 -20
- package/src/lib/components/deals-bulk-bar.js.map +1 -1
- package/src/lib/components/deals-section.d.ts +3 -3
- package/src/lib/components/deals-section.js +123 -63
- package/src/lib/components/deals-section.js.map +1 -1
- package/src/lib/components/fields-section.js +31 -17
- package/src/lib/components/fields-section.js.map +1 -1
- package/src/lib/components/lead-convert-dialog.d.ts +4 -0
- package/src/lib/components/lead-convert-dialog.js +23 -1
- package/src/lib/components/lead-convert-dialog.js.map +1 -1
- package/src/lib/components/lead-detail-page.js +8 -2
- package/src/lib/components/lead-detail-page.js.map +1 -1
- package/src/lib/components/lead-profile-fields.d.ts +71 -0
- package/src/lib/components/lead-profile-fields.js +386 -0
- package/src/lib/components/lead-profile-fields.js.map +1 -0
- package/src/lib/components/lead-properties-card.d.ts +2 -1
- package/src/lib/components/lead-properties-card.js +85 -176
- package/src/lib/components/lead-properties-card.js.map +1 -1
- package/src/lib/components/lead-source-select.d.ts +4 -23
- package/src/lib/components/lead-source-select.js +9 -73
- package/src/lib/components/lead-source-select.js.map +1 -1
- package/src/lib/components/lead-status-chip.d.ts +9 -3
- package/src/lib/components/lead-status-chip.js +8 -4
- package/src/lib/components/lead-status-chip.js.map +1 -1
- package/src/lib/components/lead-status-options.d.ts +20 -0
- package/src/lib/components/lead-status-options.js +51 -0
- package/src/lib/components/lead-status-options.js.map +1 -0
- package/src/lib/components/lead-unqualify-dialog.d.ts +5 -0
- package/src/lib/components/lead-unqualify-dialog.js +50 -18
- package/src/lib/components/lead-unqualify-dialog.js.map +1 -1
- package/src/lib/components/leads-bulk-bar.d.ts +0 -3
- package/src/lib/components/leads-bulk-bar.js +29 -29
- package/src/lib/components/leads-bulk-bar.js.map +1 -1
- package/src/lib/components/leads-section.js +120 -68
- package/src/lib/components/leads-section.js.map +1 -1
- package/src/lib/components/linked-deals-card.d.ts +4 -0
- package/src/lib/components/linked-deals-card.js +47 -3
- package/src/lib/components/linked-deals-card.js.map +1 -1
- package/src/lib/components/log-activity-dialog.js +43 -3
- package/src/lib/components/log-activity-dialog.js.map +1 -1
- package/src/lib/components/new-contact-drawer.d.ts +8 -0
- package/src/lib/components/new-contact-drawer.js +108 -6
- package/src/lib/components/new-contact-drawer.js.map +1 -1
- package/src/lib/components/new-lead-drawer.d.ts +9 -2
- package/src/lib/components/new-lead-drawer.js +88 -121
- package/src/lib/components/new-lead-drawer.js.map +1 -1
- package/src/lib/components/picklist-select.d.ts +36 -0
- package/src/lib/components/picklist-select.js +114 -0
- package/src/lib/components/picklist-select.js.map +1 -0
- package/src/lib/components/picklist-values-card.d.ts +34 -0
- package/src/lib/components/{lead-source-values-card.js → picklist-values-card.js} +241 -58
- package/src/lib/components/picklist-values-card.js.map +1 -0
- package/src/lib/components/pipeline-stages-dialog.d.ts +7 -0
- package/src/lib/components/pipeline-stages-dialog.js +26 -4
- package/src/lib/components/pipeline-stages-dialog.js.map +1 -1
- package/src/lib/components/pipelines-dialog.js +15 -6
- package/src/lib/components/pipelines-dialog.js.map +1 -1
- package/src/lib/components/recent-activity-feed.js +20 -5
- package/src/lib/components/recent-activity-feed.js.map +1 -1
- package/src/lib/components/recipes-card.js +4 -2
- package/src/lib/components/recipes-card.js.map +1 -1
- package/src/lib/components/record-tasks-card.js +15 -8
- package/src/lib/components/record-tasks-card.js.map +1 -1
- package/src/lib/components/reports/forecast-card.d.ts +6 -0
- package/src/lib/components/reports/forecast-card.js +101 -3
- package/src/lib/components/reports/forecast-card.js.map +1 -1
- package/src/lib/components/reports/lead-funnel-card.d.ts +12 -0
- package/src/lib/components/reports/lead-funnel-card.js +9 -5
- package/src/lib/components/reports/lead-funnel-card.js.map +1 -1
- package/src/lib/components/reports/lead-source-card.d.ts +23 -0
- package/src/lib/components/reports/lead-source-card.js +318 -0
- package/src/lib/components/reports/lead-source-card.js.map +1 -0
- package/src/lib/components/reports/report-export.js +1 -1
- package/src/lib/components/reports/report-export.js.map +1 -1
- package/src/lib/components/reports-section.js +8 -0
- package/src/lib/components/reports-section.js.map +1 -1
- package/src/lib/components/sharing-rule-drawer.d.ts +5 -0
- package/src/lib/components/sharing-rule-drawer.js +108 -19
- package/src/lib/components/sharing-rule-drawer.js.map +1 -1
- package/src/lib/components/sharing-rules-card.js +11 -3
- package/src/lib/components/sharing-rules-card.js.map +1 -1
- package/src/lib/components/task-cells.d.ts +9 -1
- package/src/lib/components/task-cells.js +9 -4
- package/src/lib/components/task-cells.js.map +1 -1
- package/src/lib/components/task-edit-drawer.js +111 -43
- package/src/lib/components/task-edit-drawer.js.map +1 -1
- package/src/lib/components/tasks-bulk-bar.d.ts +0 -3
- package/src/lib/components/tasks-bulk-bar.js +7 -20
- package/src/lib/components/tasks-bulk-bar.js.map +1 -1
- package/src/lib/components/tasks-calendar.d.ts +3 -0
- package/src/lib/components/tasks-calendar.js +8 -1
- package/src/lib/components/tasks-calendar.js.map +1 -1
- package/src/lib/components/tasks-section.d.ts +3 -3
- package/src/lib/components/tasks-section.js +58 -43
- package/src/lib/components/tasks-section.js.map +1 -1
- package/src/lib/constants/api-routes.d.ts +2 -9
- package/src/lib/constants/api-routes.js +1 -7
- package/src/lib/constants/api-routes.js.map +1 -1
- package/src/lib/constants/bundle-common.d.ts +6 -0
- package/src/lib/constants/bundle-common.js +11 -0
- package/src/lib/constants/bundle-common.js.map +1 -1
- package/src/lib/constants/company-filters.d.ts +14 -0
- package/src/lib/constants/company-filters.js +51 -1
- package/src/lib/constants/company-filters.js.map +1 -1
- package/src/lib/constants/contact-filters.d.ts +2 -0
- package/src/lib/constants/contact-filters.js +18 -1
- package/src/lib/constants/contact-filters.js.map +1 -1
- package/src/lib/constants/deal-filters.d.ts +22 -1
- package/src/lib/constants/deal-filters.js +67 -4
- package/src/lib/constants/deal-filters.js.map +1 -1
- package/src/lib/declarations.console-server.d.ts +3 -0
- package/src/lib/declarations.console-server.js +35 -0
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/declarations.d.ts +26 -0
- package/src/lib/declarations.js +35 -0
- package/src/lib/declarations.js.map +1 -0
- package/src/lib/declarations.server.d.ts +11 -0
- package/src/lib/declarations.server.js +92 -1
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/hooks/use-company-picklists.d.ts +15 -0
- package/src/lib/hooks/use-company-picklists.js +55 -0
- package/src/lib/hooks/use-company-picklists.js.map +1 -0
- package/src/lib/hooks/use-crm-picklist.d.ts +25 -0
- package/src/lib/hooks/use-crm-picklist.js +53 -0
- package/src/lib/hooks/use-crm-picklist.js.map +1 -0
- package/src/lib/hooks/use-crm-record-names.d.ts +16 -0
- package/src/lib/hooks/use-crm-record-names.js +45 -19
- package/src/lib/hooks/use-crm-record-names.js.map +1 -1
- package/src/lib/hooks/use-crm-task-picklists.d.ts +11 -0
- package/src/lib/hooks/use-crm-task-picklists.js +45 -0
- package/src/lib/hooks/use-crm-task-picklists.js.map +1 -0
- package/src/lib/hooks/use-deals.d.ts +14 -0
- package/src/lib/hooks/use-deals.js +29 -0
- package/src/lib/hooks/use-deals.js.map +1 -1
- package/src/lib/hooks/use-lead-picklists.d.ts +14 -0
- package/src/lib/hooks/use-lead-picklists.js +46 -0
- package/src/lib/hooks/use-lead-picklists.js.map +1 -0
- package/src/lib/hooks/use-lead-source-picklist.d.ts +5 -19
- package/src/lib/hooks/use-lead-source-picklist.js +12 -22
- package/src/lib/hooks/use-lead-source-picklist.js.map +1 -1
- package/src/lib/hooks/use-lead-status-picklist.d.ts +9 -0
- package/src/lib/hooks/use-lead-status-picklist.js +40 -0
- package/src/lib/hooks/use-lead-status-picklist.js.map +1 -0
- package/src/lib/model/companies.d.ts +32 -3
- package/src/lib/model/companies.js +133 -16
- package/src/lib/model/companies.js.map +1 -1
- package/src/lib/model/contact-merge.d.ts +27 -3
- package/src/lib/model/contact-merge.js +81 -7
- package/src/lib/model/contact-merge.js.map +1 -1
- package/src/lib/model/contact-record.d.ts +17 -0
- package/src/lib/model/contact-record.js +15 -1
- package/src/lib/model/contact-record.js.map +1 -1
- package/src/lib/model/contact-update.d.ts +31 -2
- package/src/lib/model/contact-update.js +14 -0
- package/src/lib/model/contact-update.js.map +1 -1
- package/src/lib/model/crm-list-query.d.ts +5 -0
- package/src/lib/model/crm-list-query.js +8 -0
- package/src/lib/model/crm-list-query.js.map +1 -1
- package/src/lib/model/crm-recipes.d.ts +40 -0
- package/src/lib/model/crm-recipes.js +244 -0
- package/src/lib/model/crm-recipes.js.map +1 -0
- package/src/lib/model/crm-record-counts.d.ts +36 -0
- package/src/lib/model/crm-record-counts.js +54 -0
- package/src/lib/model/crm-record-counts.js.map +1 -0
- package/src/lib/model/crm-record-lists.d.ts +23 -0
- package/src/lib/model/crm-record-lists.js +161 -0
- package/src/lib/model/crm-record-lists.js.map +1 -0
- package/src/lib/model/crm-reports.d.ts +73 -3
- package/src/lib/model/crm-reports.js +120 -1
- package/src/lib/model/crm-reports.js.map +1 -1
- package/src/lib/model/crm-sharing.d.ts +21 -3
- package/src/lib/model/crm-sharing.js +27 -6
- package/src/lib/model/crm-sharing.js.map +1 -1
- package/src/lib/model/deal-board-model.d.ts +8 -2
- package/src/lib/model/deal-board-model.js +15 -2
- package/src/lib/model/deal-board-model.js.map +1 -1
- package/src/lib/model/deal-contact-roles.d.ts +45 -0
- package/src/lib/model/deal-contact-roles.js +73 -0
- package/src/lib/model/deal-contact-roles.js.map +1 -0
- package/src/lib/model/deal-form-model.d.ts +56 -0
- package/src/lib/model/deal-form-model.js +79 -7
- package/src/lib/model/deal-form-model.js.map +1 -1
- package/src/lib/model/download-text-file.d.ts +23 -0
- package/src/lib/model/download-text-file.js +34 -0
- package/src/lib/model/download-text-file.js.map +1 -0
- package/src/lib/model/lead-filters.d.ts +36 -2
- package/src/lib/model/lead-filters.js +123 -2
- package/src/lib/model/lead-filters.js.map +1 -1
- package/src/lib/model/lead-source-direction.d.ts +38 -0
- package/src/lib/model/lead-source-direction.js +52 -0
- package/src/lib/model/lead-source-direction.js.map +1 -0
- package/src/lib/model/picklist-values.d.ts +119 -0
- package/src/lib/model/picklist-values.js +256 -0
- package/src/lib/model/picklist-values.js.map +1 -0
- package/src/lib/model/record-facts-disclosed.d.ts +81 -0
- package/src/lib/model/record-facts-disclosed.js +281 -0
- package/src/lib/model/record-facts-disclosed.js.map +1 -0
- package/src/lib/model/record-facts.d.ts +215 -34
- package/src/lib/model/record-facts.js +307 -128
- package/src/lib/model/record-facts.js.map +1 -1
- package/src/lib/model/task-picklists.d.ts +52 -0
- package/src/lib/model/task-picklists.js +83 -0
- package/src/lib/model/task-picklists.js.map +1 -0
- package/src/lib/model/task-routes.d.ts +13 -0
- package/src/lib/model/task-routes.js +23 -4
- package/src/lib/model/task-routes.js.map +1 -1
- package/src/lib/plan-entitlements.js +6 -4
- package/src/lib/plan-entitlements.js.map +1 -1
- package/src/lib/plugin.js +17 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/api-v1/contacts.js +220 -14
- package/src/lib/server/api-v1/contacts.js.map +1 -1
- package/src/lib/server/api-v1/crm-activities.js +14 -1
- package/src/lib/server/api-v1/crm-activities.js.map +1 -1
- package/src/lib/server/api-v1/crm-companies.js +123 -14
- package/src/lib/server/api-v1/crm-companies.js.map +1 -1
- package/src/lib/server/api-v1/crm-deals.js +291 -26
- package/src/lib/server/api-v1/crm-deals.js.map +1 -1
- package/src/lib/server/api-v1/crm-leads.js +144 -38
- package/src/lib/server/api-v1/crm-leads.js.map +1 -1
- package/src/lib/server/api-v1/crm-pipelines.d.ts +6 -0
- package/src/lib/server/api-v1/crm-pipelines.js +8 -2
- package/src/lib/server/api-v1/crm-pipelines.js.map +1 -1
- package/src/lib/server/api-v1/crm-tasks.js +75 -33
- package/src/lib/server/api-v1/crm-tasks.js.map +1 -1
- package/src/lib/server/api-v1/openapi.d.ts +0 -11
- package/src/lib/server/api-v1/openapi.js +171 -16
- package/src/lib/server/api-v1/openapi.js.map +1 -1
- package/src/lib/server/assign-contact-owner.d.ts +162 -0
- package/src/lib/server/assign-contact-owner.js +340 -0
- package/src/lib/server/assign-contact-owner.js.map +1 -0
- package/src/lib/server/associate-company-by-domain.d.ts +70 -0
- package/src/lib/server/associate-company-by-domain.js +153 -0
- package/src/lib/server/associate-company-by-domain.js.map +1 -0
- package/src/lib/server/automation-steps.d.ts +139 -0
- package/src/lib/server/automation-steps.js +472 -0
- package/src/lib/server/automation-steps.js.map +1 -0
- package/src/lib/server/capture-contact.js +69 -22
- package/src/lib/server/capture-contact.js.map +1 -1
- package/src/lib/server/capture-host-contact.d.ts +104 -0
- package/src/lib/server/capture-host-contact.js +151 -0
- package/src/lib/server/capture-host-contact.js.map +1 -0
- package/src/lib/server/company-children.d.ts +25 -0
- package/src/lib/server/company-children.js +42 -0
- package/src/lib/server/company-children.js.map +1 -0
- package/src/lib/server/company-delete.d.ts +18 -0
- package/src/lib/server/company-delete.js +44 -21
- package/src/lib/server/company-delete.js.map +1 -1
- package/src/lib/server/contact-email-history.js +21 -19
- package/src/lib/server/contact-email-history.js.map +1 -1
- package/src/lib/server/contact-remove.js +27 -2
- package/src/lib/server/contact-remove.js.map +1 -1
- package/src/lib/server/contact-reports-to.d.ts +61 -0
- package/src/lib/server/contact-reports-to.js +114 -0
- package/src/lib/server/contact-reports-to.js.map +1 -0
- package/src/lib/server/contact-update.d.ts +42 -1
- package/src/lib/server/contact-update.js +204 -23
- package/src/lib/server/contact-update.js.map +1 -1
- package/src/lib/server/convert-host-lead.d.ts +46 -1
- package/src/lib/server/convert-host-lead.js +173 -15
- package/src/lib/server/convert-host-lead.js.map +1 -1
- package/src/lib/server/convert-open-lead.js +12 -5
- package/src/lib/server/convert-open-lead.js.map +1 -1
- package/src/lib/server/crm-record-indexes.d.ts +45 -0
- package/src/lib/server/crm-record-indexes.js +78 -0
- package/src/lib/server/crm-record-indexes.js.map +1 -0
- package/src/lib/server/crm-sharing.d.ts +9 -1
- package/src/lib/server/crm-sharing.js +23 -3
- package/src/lib/server/crm-sharing.js.map +1 -1
- package/src/lib/server/deal-contact-roles.d.ts +27 -0
- package/src/lib/server/deal-contact-roles.js +89 -0
- package/src/lib/server/deal-contact-roles.js.map +1 -0
- package/src/lib/server/lead-convert.d.ts +5 -0
- package/src/lib/server/lead-convert.js +19 -3
- package/src/lib/server/lead-convert.js.map +1 -1
- package/src/lib/server/lead-create.d.ts +17 -2
- package/src/lib/server/lead-create.js +46 -14
- package/src/lib/server/lead-create.js.map +1 -1
- package/src/lib/server/lead-nurturing.d.ts +6 -0
- package/src/lib/server/lead-nurturing.js +57 -20
- package/src/lib/server/lead-nurturing.js.map +1 -1
- package/src/lib/server/lead-picklists.d.ts +35 -0
- package/src/lib/server/lead-picklists.js +52 -0
- package/src/lib/server/lead-picklists.js.map +1 -0
- package/src/lib/server/lead-source-picklist.d.ts +1 -13
- package/src/lib/server/lead-source-picklist.js +6 -33
- package/src/lib/server/lead-source-picklist.js.map +1 -1
- package/src/lib/server/merge-contacts.js +22 -4
- package/src/lib/server/merge-contacts.js.map +1 -1
- package/src/lib/server/person-eraser.d.ts +53 -0
- package/src/lib/server/person-eraser.js +149 -0
- package/src/lib/server/person-eraser.js.map +1 -0
- package/src/lib/server/person-records.d.ts +69 -0
- package/src/lib/server/person-records.js +317 -0
- package/src/lib/server/person-records.js.map +1 -0
- package/src/lib/server/person-refund.d.ts +97 -0
- package/src/lib/server/person-refund.js +221 -0
- package/src/lib/server/person-refund.js.map +1 -0
- package/src/lib/server/picklist-values.d.ts +21 -0
- package/src/lib/server/picklist-values.js +308 -0
- package/src/lib/server/picklist-values.js.map +1 -0
- package/src/lib/server/read-picklist.d.ts +44 -0
- package/src/lib/server/read-picklist.js +65 -0
- package/src/lib/server/read-picklist.js.map +1 -0
- package/src/lib/server/recipe-routes.js +15 -7
- package/src/lib/server/recipe-routes.js.map +1 -1
- package/src/lib/server/record-email-state.js +7 -1
- package/src/lib/server/record-email-state.js.map +1 -1
- package/src/lib/server/record-facts.d.ts +3 -0
- package/src/lib/server/record-facts.js +233 -31
- package/src/lib/server/record-facts.js.map +1 -1
- package/src/lib/server/record-origin.d.ts +27 -0
- package/src/lib/server/record-origin.js +104 -0
- package/src/lib/server/record-origin.js.map +1 -0
- package/src/lib/server/record-timeline.js +15 -2
- package/src/lib/server/record-timeline.js.map +1 -1
- package/src/lib/server/suite-gate.js +4 -3
- package/src/lib/server/suite-gate.js.map +1 -1
- package/src/lib/server/task-routes.js +30 -16
- package/src/lib/server/task-routes.js.map +1 -1
- package/src/lib/server-deal-stage.d.ts +5 -1
- package/src/lib/server-deal-stage.js +10 -5
- package/src/lib/server-deal-stage.js.map +1 -1
- package/src/lib/server.d.ts +8 -3
- package/src/lib/server.js +47 -43
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/memory-firestore.d.ts +55 -0
- package/src/lib/testing/memory-firestore.js +335 -0
- package/src/lib/testing/memory-firestore.js.map +1 -0
- package/src/lib/testing/stand-in-email-send-index.d.ts +25 -0
- package/src/lib/testing/stand-in-email-send-index.js +49 -0
- package/src/lib/testing/stand-in-email-send-index.js.map +1 -0
- package/src/lib/transfer/activities.d.ts +30 -0
- package/src/lib/transfer/activities.js +132 -0
- package/src/lib/transfer/activities.js.map +1 -0
- package/src/lib/transfer/aliases.d.ts +22 -0
- package/src/lib/transfer/aliases.js +1342 -0
- package/src/lib/transfer/aliases.js.map +1 -0
- package/src/lib/transfer/common.d.ts +222 -0
- package/src/lib/transfer/common.js +832 -0
- package/src/lib/transfer/common.js.map +1 -0
- package/src/lib/transfer/companies.d.ts +43 -0
- package/src/lib/transfer/companies.js +549 -0
- package/src/lib/transfer/companies.js.map +1 -0
- package/src/lib/transfer/contacts.d.ts +31 -0
- package/src/lib/transfer/contacts.js +727 -0
- package/src/lib/transfer/contacts.js.map +1 -0
- package/src/lib/transfer/deals.d.ts +66 -0
- package/src/lib/transfer/deals.js +698 -0
- package/src/lib/transfer/deals.js.map +1 -0
- package/src/lib/transfer/email-templates-package.d.ts +40 -0
- package/src/lib/transfer/email-templates-package.js +76 -0
- package/src/lib/transfer/email-templates-package.js.map +1 -0
- package/src/lib/transfer/email-templates-package.server.d.ts +32 -0
- package/src/lib/transfer/email-templates-package.server.js +176 -0
- package/src/lib/transfer/email-templates-package.server.js.map +1 -0
- package/src/lib/transfer/fields.d.ts +102 -0
- package/src/lib/transfer/fields.js +1755 -0
- package/src/lib/transfer/fields.js.map +1 -0
- package/src/lib/transfer/leads.d.ts +30 -0
- package/src/lib/transfer/leads.js +582 -0
- package/src/lib/transfer/leads.js.map +1 -0
- package/src/lib/transfer/pipelines.d.ts +21 -0
- package/src/lib/transfer/pipelines.js +172 -0
- package/src/lib/transfer/pipelines.js.map +1 -0
- package/src/lib/transfer/register.d.ts +47 -0
- package/src/lib/transfer/register.js +277 -0
- package/src/lib/transfer/register.js.map +1 -0
- package/src/lib/transfer/tasks.d.ts +30 -0
- package/src/lib/transfer/tasks.js +418 -0
- package/src/lib/transfer/tasks.js.map +1 -0
- package/src/lib/transfer/ui.d.ts +20 -0
- package/src/lib/transfer/ui.js +42 -0
- package/src/lib/transfer/ui.js.map +1 -0
- package/src/lib/components/company-import-drawer.d.ts +0 -42
- package/src/lib/components/company-import-drawer.js +0 -99
- package/src/lib/components/company-import-drawer.js.map +0 -1
- package/src/lib/components/contact-import-drawer.d.ts +0 -46
- package/src/lib/components/contact-import-drawer.js +0 -149
- package/src/lib/components/contact-import-drawer.js.map +0 -1
- package/src/lib/components/crm-export-all-button.d.ts +0 -39
- package/src/lib/components/crm-export-all-button.js +0 -98
- package/src/lib/components/crm-export-all-button.js.map +0 -1
- package/src/lib/components/csv-import-drawer.d.ts +0 -139
- package/src/lib/components/csv-import-drawer.js +0 -757
- package/src/lib/components/csv-import-drawer.js.map +0 -1
- package/src/lib/components/deal-import-drawer.d.ts +0 -24
- package/src/lib/components/deal-import-drawer.js +0 -83
- package/src/lib/components/deal-import-drawer.js.map +0 -1
- package/src/lib/components/lead-import-drawer.d.ts +0 -27
- package/src/lib/components/lead-import-drawer.js +0 -118
- package/src/lib/components/lead-import-drawer.js.map +0 -1
- package/src/lib/components/lead-source-values-card.d.ts +0 -27
- package/src/lib/components/lead-source-values-card.js.map +0 -1
- package/src/lib/components/task-import-drawer.d.ts +0 -24
- package/src/lib/components/task-import-drawer.js +0 -82
- package/src/lib/components/task-import-drawer.js.map +0 -1
- package/src/lib/model/companies-csv.d.ts +0 -36
- package/src/lib/model/companies-csv.js +0 -38
- package/src/lib/model/companies-csv.js.map +0 -1
- package/src/lib/model/contacts-csv.d.ts +0 -54
- package/src/lib/model/contacts-csv.js +0 -67
- package/src/lib/model/contacts-csv.js.map +0 -1
- package/src/lib/model/crm-company-import.d.ts +0 -154
- package/src/lib/model/crm-company-import.js +0 -331
- package/src/lib/model/crm-company-import.js.map +0 -1
- package/src/lib/model/crm-csv.d.ts +0 -239
- package/src/lib/model/crm-csv.js +0 -467
- package/src/lib/model/crm-csv.js.map +0 -1
- package/src/lib/model/crm-deal-import.d.ts +0 -112
- package/src/lib/model/crm-deal-import.js +0 -263
- package/src/lib/model/crm-deal-import.js.map +0 -1
- package/src/lib/model/crm-import.d.ts +0 -250
- package/src/lib/model/crm-import.js +0 -467
- package/src/lib/model/crm-import.js.map +0 -1
- package/src/lib/model/crm-lead-import.d.ts +0 -138
- package/src/lib/model/crm-lead-import.js +0 -446
- package/src/lib/model/crm-lead-import.js.map +0 -1
- package/src/lib/model/crm-task-import.d.ts +0 -94
- package/src/lib/model/crm-task-import.js +0 -275
- package/src/lib/model/crm-task-import.js.map +0 -1
- package/src/lib/model/deals-csv.d.ts +0 -32
- package/src/lib/model/deals-csv.js +0 -36
- package/src/lib/model/deals-csv.js.map +0 -1
- package/src/lib/model/import-column-shapes.d.ts +0 -36
- package/src/lib/model/import-column-shapes.js +0 -76
- package/src/lib/model/import-column-shapes.js.map +0 -1
- package/src/lib/model/lead-source-values.d.ts +0 -82
- package/src/lib/model/lead-source-values.js +0 -149
- package/src/lib/model/lead-source-values.js.map +0 -1
- package/src/lib/model/leads-csv.d.ts +0 -40
- package/src/lib/model/leads-csv.js +0 -40
- package/src/lib/model/leads-csv.js.map +0 -1
- package/src/lib/model/tasks-csv.d.ts +0 -28
- package/src/lib/model/tasks-csv.js +0 -28
- package/src/lib/model/tasks-csv.js.map +0 -1
- package/src/lib/server/companies-import.d.ts +0 -57
- package/src/lib/server/companies-import.js +0 -242
- package/src/lib/server/companies-import.js.map +0 -1
- package/src/lib/server/contacts-import.d.ts +0 -109
- package/src/lib/server/contacts-import.js +0 -393
- package/src/lib/server/contacts-import.js.map +0 -1
- package/src/lib/server/deals-import.d.ts +0 -76
- package/src/lib/server/deals-import.js +0 -248
- package/src/lib/server/deals-import.js.map +0 -1
- package/src/lib/server/export-route.d.ts +0 -60
- package/src/lib/server/export-route.js +0 -447
- package/src/lib/server/export-route.js.map +0 -1
- package/src/lib/server/import-context.d.ts +0 -87
- package/src/lib/server/import-context.js +0 -182
- package/src/lib/server/import-context.js.map +0 -1
- package/src/lib/server/lead-source-values.d.ts +0 -50
- package/src/lib/server/lead-source-values.js +0 -191
- package/src/lib/server/lead-source-values.js.map +0 -1
- package/src/lib/server/leads-import.d.ts +0 -84
- package/src/lib/server/leads-import.js +0 -367
- package/src/lib/server/leads-import.js.map +0 -1
- package/src/lib/server/tasks-import.d.ts +0 -54
- package/src/lib/server/tasks-import.js +0 -160
- package/src/lib/server/tasks-import.js.map +0 -1
|
@@ -0,0 +1,832 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ /*==========================================
|
|
18
|
+
* WHAT EVERY CRM TRANSFER RESOURCE SHARES (AGL-3527) — the server half.
|
|
19
|
+
*
|
|
20
|
+
* The CRM's records live under the organization, each stamped with the
|
|
21
|
+
* site that captured it and the `visibleTo` tokens that say who reads it.
|
|
22
|
+
* A transfer is opened from the CRM under a site, or at the organization
|
|
23
|
+
* level; the job engine hands every hook the workspace and that site
|
|
24
|
+
* (`ctx.hostId`), and this module turns the pair into what the CRM's own
|
|
25
|
+
* routes compute from a request: the org document, the site's consent
|
|
26
|
+
* group, the tokens a record must carry to be seen from the site, and the
|
|
27
|
+
* stamp a record created by the import carries.
|
|
28
|
+
*
|
|
29
|
+
* ## Refusals are the routes' refusals
|
|
30
|
+
*
|
|
31
|
+
* The transfer routes check `data.manage`, and the CRM's suite on the plan
|
|
32
|
+
* through each resource's `planGate` (AGL-3555). What is particular to the
|
|
33
|
+
* CRM — the suite again where a hook reads or writes, a site to file new
|
|
34
|
+
* records under — is checked here and thrown as the engine's own errors
|
|
35
|
+
* (`TransferPlanRefusedError` carrying `suite-gate.ts`'s answer, else
|
|
36
|
+
* `TransferEngineError`), so the wizard shows the sentence a CRM route
|
|
37
|
+
* would have answered.
|
|
38
|
+
*=========================================*/ import { checkCrmRecordsQuota, consentGroupForHost, CRM_COLLECTIONS, crmPicklistDefinition, crmReadTokens, crmScopeTokens, effectiveCrmPicklist, fieldDefinitionsForObject, isCrmPicklistId, newResourceScopeFields, normalizeCrmPicklist, ORG_SCOPE_TOKEN, readCrmCustomInput, visibleToTokens } from "@aglyn/aglyn/server";
|
|
39
|
+
import { CONTACT_LIFECYCLE_STAGE_LABELS, CONTACT_LIFECYCLE_STAGES, CRM_FORECAST_CATEGORIES, CRM_FORECAST_CATEGORY_LABELS } from "@aglyn/aglyn/app-utils/crm";
|
|
40
|
+
import { visibleToHost } from "@aglyn/aglyn/app-utils/scope-tokens";
|
|
41
|
+
import { listOrgContainers } from "@aglyn/tenant-data-admin/server/org-containers";
|
|
42
|
+
import { normalizeAddress } from "@aglyn/aglyn/foundation/definitions/contact.types";
|
|
43
|
+
import { matchLookupKey, rankTransferLookupSuggestions, transferLookupKey } from "@aglyn/aglyn/data-transfer";
|
|
44
|
+
import { crmRecordsQuotaForOrg, firebaseAdmin, listOrgMembers } from "@aglyn/tenant-data-admin";
|
|
45
|
+
import { applyListQuery } from "@aglyn/tenant-data-admin/server/list-query";
|
|
46
|
+
import { TransferEngineError, TransferPlanRefusedError } from "@aglyn/tenant-data-admin/server/transfer-jobs";
|
|
47
|
+
import { FieldPath, FieldValue, Timestamp } from "firebase-admin/firestore";
|
|
48
|
+
import { crmSuiteRefusal } from "../server/suite-gate.js";
|
|
49
|
+
import { CRM_ADDRESS_PART_KEYS, CRM_ADDRESS_PARTS, CRM_CAMPAIGNS_PICKLIST, CRM_FORECAST_CATEGORY_PICKLIST, CRM_LIFECYCLE_STAGE_PICKLIST, crmCustomPicklistKey } from "./fields.js";
|
|
50
|
+
/** The most values one Firestore `in` filter takes. */ export const IN_LIMIT = 30;
|
|
51
|
+
/** Documents read per page of an export. */ export const EXPORT_PAGE = 500;
|
|
52
|
+
/** Rows written at once by an apply. */ export const APPLY_CONCURRENCY = 8;
|
|
53
|
+
/** A row is started only while this much of the chunk's budget is left. */ export const APPLY_ROW_BUDGET_MS = 3000;
|
|
54
|
+
/** The org, the site and its tokens, for one hook call. */ export async function crmTransferEnv(ctx) {
|
|
55
|
+
var _snapshot_data;
|
|
56
|
+
const firestore = firebaseAdmin.app().firestore();
|
|
57
|
+
const orgRef = firestore.collection('orgs').doc(ctx.orgId);
|
|
58
|
+
const snapshot = await orgRef.get();
|
|
59
|
+
if (!snapshot.exists) throw new TransferEngineError('notFound', 404, 'No such workspace.');
|
|
60
|
+
const org = (_snapshot_data = snapshot.data()) != null ? _snapshot_data : {};
|
|
61
|
+
const group = ctx.hostId ? consentGroupForHost(org, ctx.hostId) : null;
|
|
62
|
+
return {
|
|
63
|
+
firestore,
|
|
64
|
+
orgRef,
|
|
65
|
+
org,
|
|
66
|
+
orgId: ctx.orgId,
|
|
67
|
+
hostId: ctx.hostId,
|
|
68
|
+
group,
|
|
69
|
+
siteTokens: group ? crmReadTokens(group) : null
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Refuses an act the organization's plan does not include, in the CRM
|
|
74
|
+
* routes' own answer (`suite-gate.ts`). The transfer gate already asked
|
|
75
|
+
* (AGL-3555, each resource's `planGate`); a hook asks again where it reads
|
|
76
|
+
* or writes, so a caller that reaches it without the gate is refused alike.
|
|
77
|
+
*/ export function requireCrmSuite(env, act) {
|
|
78
|
+
const refusal = crmSuiteRefusal(env.org, act);
|
|
79
|
+
if (refusal) throw new TransferPlanRefusedError(refusal);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Refuses reading the CRM's own records (not the people files) on a plan
|
|
83
|
+
* without the CRM: the export route's rule since AGL-2839.
|
|
84
|
+
*/ export function requireCrmRecords(env, what) {
|
|
85
|
+
requireCrmSuite(env, `Exporting ${what}`);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The site new records are filed under, or the refusal: every CRM record is
|
|
89
|
+
* a fact some site met, so an import opened at the organization level must
|
|
90
|
+
* name one first.
|
|
91
|
+
*/ export function requireSite(env, what) {
|
|
92
|
+
if (!env.hostId || !env.group) {
|
|
93
|
+
throw new TransferEngineError('invalid', 400, `Choose the site these ${what} are imported into.`);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
hostId: env.hostId,
|
|
97
|
+
group: env.group
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/** The stamp a record the import creates carries: the site, and who reads it. */ export function creationScope(env, actorUid) {
|
|
101
|
+
const { hostId, group } = requireSite(env, 'records');
|
|
102
|
+
return _extends({
|
|
103
|
+
hostId,
|
|
104
|
+
visibleTo: crmScopeTokens(env.org, group)
|
|
105
|
+
}, actorUid ? {
|
|
106
|
+
createdByUid: actorUid
|
|
107
|
+
} : {}, {
|
|
108
|
+
createdAt: FieldValue.serverTimestamp(),
|
|
109
|
+
updatedAt: FieldValue.serverTimestamp()
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/** Whether a stored record may be read in this transfer: the site's view, and a scoped reader's own tokens. */ export function visibleIn(env, visibleTo, scopeTokens) {
|
|
113
|
+
const tokens = Array.isArray(visibleTo) ? visibleTo : [];
|
|
114
|
+
if (env.siteTokens && !visibleToTokens(tokens, env.siteTokens)) return false;
|
|
115
|
+
if ((scopeTokens == null ? void 0 : scopeTokens.length) && !visibleToTokens(tokens, scopeTokens)) return false;
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
/*==========================================
|
|
119
|
+
* CUSTOM FIELDS AND PICKLISTS
|
|
120
|
+
*=========================================*/ /** The organization's live custom field definitions for one kind of record, as the site reads them. */ export async function crmCustomDefinitions(env, object) {
|
|
121
|
+
const snapshot = await env.orgRef.collection(CRM_COLLECTIONS.contactFields).limit(200).get();
|
|
122
|
+
return fieldDefinitionsForObject(snapshot.docs.map((doc)=>doc.data()), object).filter((field)=>Boolean(field.key) && !field.retiredAt && (!env.siteTokens || visibleToTokens(field.visibleTo, env.siteTokens)));
|
|
123
|
+
}
|
|
124
|
+
/** The lifecycle stages as a fixed list: matched onto, never added to. */ const LIFECYCLE_LIST = {
|
|
125
|
+
spec: {
|
|
126
|
+
restricted: true,
|
|
127
|
+
standardValues: CONTACT_LIFECYCLE_STAGES.map((id)=>({
|
|
128
|
+
id,
|
|
129
|
+
label: CONTACT_LIFECYCLE_STAGE_LABELS[id]
|
|
130
|
+
}))
|
|
131
|
+
},
|
|
132
|
+
set: {
|
|
133
|
+
values: CONTACT_LIFECYCLE_STAGES.map((id)=>({
|
|
134
|
+
id,
|
|
135
|
+
label: CONTACT_LIFECYCLE_STAGE_LABELS[id],
|
|
136
|
+
active: true
|
|
137
|
+
})),
|
|
138
|
+
defaultValueId: null
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
/** The forecast categories: a fixed set a forecast rolls up by, matched onto and never added to. */ const FORECAST_LIST = {
|
|
142
|
+
spec: {
|
|
143
|
+
restricted: true,
|
|
144
|
+
standardValues: CRM_FORECAST_CATEGORIES.map((id)=>({
|
|
145
|
+
id,
|
|
146
|
+
label: CRM_FORECAST_CATEGORY_LABELS[id]
|
|
147
|
+
}))
|
|
148
|
+
},
|
|
149
|
+
set: {
|
|
150
|
+
values: CRM_FORECAST_CATEGORIES.map((id)=>({
|
|
151
|
+
id,
|
|
152
|
+
label: CRM_FORECAST_CATEGORY_LABELS[id],
|
|
153
|
+
active: true
|
|
154
|
+
})),
|
|
155
|
+
defaultValueId: null
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* The lists behind the picklist fields a catalog names: the CRM's own
|
|
160
|
+
* (`crmPicklists`), the lifecycle stages, and each custom `select` field's
|
|
161
|
+
* options — a select is a fixed list the import maps onto.
|
|
162
|
+
*/ export async function crmPicklistLists(env, picklistIds, customDefinitions) {
|
|
163
|
+
const lists = {};
|
|
164
|
+
const crmIds = picklistIds.filter(isCrmPicklistId);
|
|
165
|
+
const snapshots = crmIds.length ? await env.firestore.getAll(...crmIds.map((id)=>env.orgRef.collection(CRM_COLLECTIONS.picklists).doc(id))) : [];
|
|
166
|
+
crmIds.forEach((id, at)=>{
|
|
167
|
+
var _snapshots_at;
|
|
168
|
+
const definition = crmPicklistDefinition(id);
|
|
169
|
+
if (!definition) return;
|
|
170
|
+
lists[id] = {
|
|
171
|
+
spec: definition,
|
|
172
|
+
set: effectiveCrmPicklist(id, (_snapshots_at = snapshots[at]) == null ? void 0 : _snapshots_at.data())
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
for (const id of picklistIds){
|
|
176
|
+
var _definition_options;
|
|
177
|
+
if (id === CRM_LIFECYCLE_STAGE_PICKLIST) {
|
|
178
|
+
lists[id] = LIFECYCLE_LIST;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (id === CRM_FORECAST_CATEGORY_PICKLIST) {
|
|
182
|
+
lists[id] = FORECAST_LIST;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (id === CRM_CAMPAIGNS_PICKLIST) {
|
|
186
|
+
const { byName, names } = await campaignDirectory(env);
|
|
187
|
+
const live = [
|
|
188
|
+
...new Set(byName.values())
|
|
189
|
+
].map((campaign)=>{
|
|
190
|
+
var _names_get;
|
|
191
|
+
return {
|
|
192
|
+
id: campaign,
|
|
193
|
+
label: (_names_get = names.get(campaign)) != null ? _names_get : campaign
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
lists[id] = {
|
|
197
|
+
spec: {
|
|
198
|
+
restricted: true,
|
|
199
|
+
standardValues: live
|
|
200
|
+
},
|
|
201
|
+
set: {
|
|
202
|
+
values: live.map((value)=>_extends({}, value, {
|
|
203
|
+
active: true
|
|
204
|
+
})),
|
|
205
|
+
defaultValueId: null
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const custom = crmCustomPicklistKey(id);
|
|
211
|
+
if (!custom) continue;
|
|
212
|
+
const definition = customDefinitions.find((entry)=>entry.key === custom.key);
|
|
213
|
+
if (!definition) continue;
|
|
214
|
+
const options = ((_definition_options = definition.options) != null ? _definition_options : []).map((option)=>String(option)).filter(Boolean);
|
|
215
|
+
lists[id] = {
|
|
216
|
+
spec: {
|
|
217
|
+
restricted: true,
|
|
218
|
+
standardValues: options.map((label, index)=>({
|
|
219
|
+
id: `o${index}`,
|
|
220
|
+
label
|
|
221
|
+
}))
|
|
222
|
+
},
|
|
223
|
+
set: {
|
|
224
|
+
values: options.map((label, index)=>({
|
|
225
|
+
id: `o${index}`,
|
|
226
|
+
label,
|
|
227
|
+
active: true
|
|
228
|
+
})),
|
|
229
|
+
defaultValueId: null
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
return lists;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Adds the values the person chose to add to one of the CRM's picklists —
|
|
237
|
+
* in a transaction, so an admin editing the list at the same moment loses
|
|
238
|
+
* nothing — skipping an id or a label the list already holds, so a retried
|
|
239
|
+
* apply adds nothing twice. A value whose meaning only the platform sets
|
|
240
|
+
* (a lead Qualified by conversion) is never added. Fixed lists (the stages,
|
|
241
|
+
* a select's options) take nothing.
|
|
242
|
+
*/ export async function addCrmPicklistValues(env, picklistId, values) {
|
|
243
|
+
if (!isCrmPicklistId(picklistId)) return;
|
|
244
|
+
const definition = crmPicklistDefinition(picklistId);
|
|
245
|
+
if (!definition) return;
|
|
246
|
+
const ref = env.orgRef.collection(CRM_COLLECTIONS.picklists).doc(picklistId);
|
|
247
|
+
await env.firestore.runTransaction(async (transaction)=>{
|
|
248
|
+
const snapshot = await transaction.get(ref);
|
|
249
|
+
const current = effectiveCrmPicklist(picklistId, snapshot.data());
|
|
250
|
+
const held = new Set(current.values.map((value)=>value.id));
|
|
251
|
+
const labels = new Set(current.values.map((value)=>value.label.toLowerCase()));
|
|
252
|
+
const added = values.filter((value)=>{
|
|
253
|
+
var _definition_reservedMeanings;
|
|
254
|
+
return !held.has(value.id) && !labels.has(value.label.toLowerCase()) && !(value.meaning && ((_definition_reservedMeanings = definition.reservedMeanings) == null ? void 0 : _definition_reservedMeanings.includes(value.meaning)));
|
|
255
|
+
});
|
|
256
|
+
if (!added.length) return;
|
|
257
|
+
const created = normalizeCrmPicklist(snapshot.data()) === null;
|
|
258
|
+
transaction.set(ref, _extends({
|
|
259
|
+
values: [
|
|
260
|
+
...current.values,
|
|
261
|
+
...added.map((value)=>_extends({}, value, {
|
|
262
|
+
active: true
|
|
263
|
+
}))
|
|
264
|
+
],
|
|
265
|
+
defaultValueId: current.defaultValueId,
|
|
266
|
+
updatedAt: FieldValue.serverTimestamp()
|
|
267
|
+
}, created ? _extends({
|
|
268
|
+
hostId: env.hostId,
|
|
269
|
+
createdAt: FieldValue.serverTimestamp()
|
|
270
|
+
}, newResourceScopeFields([
|
|
271
|
+
ORG_SCOPE_TOKEN
|
|
272
|
+
])) : {}), {
|
|
273
|
+
merge: true
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
/*==========================================
|
|
278
|
+
* CAMPAIGNS — named by a deal's and a lead's campaign columns
|
|
279
|
+
*=========================================*/ /** The most campaigns a file's names are resolved against — the lead import's own ceiling. */ const CAMPAIGN_CEILING = 200;
|
|
280
|
+
/**
|
|
281
|
+
* The organization's live campaigns, by lowercased name and by id. A name
|
|
282
|
+
* two campaigns share resolves to the one placed on the transfer's site
|
|
283
|
+
* first, as the lead import resolved it.
|
|
284
|
+
*/ export async function campaignDirectory(env) {
|
|
285
|
+
const byName = new Map();
|
|
286
|
+
const names = new Map();
|
|
287
|
+
const containers = await listOrgContainers(env.firestore, 'campaign', env.orgId, CAMPAIGN_CEILING).catch(()=>[]);
|
|
288
|
+
const live = containers.filter((container)=>container.live);
|
|
289
|
+
const placed = (visibleTo)=>env.hostId ? visibleToHost(visibleTo, env.hostId) : true;
|
|
290
|
+
for (const container of [
|
|
291
|
+
...live.filter((entry)=>placed(entry.visibleTo)),
|
|
292
|
+
...live.filter((entry)=>!placed(entry.visibleTo))
|
|
293
|
+
]){
|
|
294
|
+
const key = container.name.toLowerCase();
|
|
295
|
+
if (key && !byName.has(key)) byName.set(key, container.id);
|
|
296
|
+
}
|
|
297
|
+
for (const container of containers)if (container.name) names.set(container.id, container.name);
|
|
298
|
+
return {
|
|
299
|
+
byName,
|
|
300
|
+
names
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
async function memberEntries(orgId) {
|
|
304
|
+
return (await listOrgMembers(orgId)).filter((member)=>member.$id && member.orgSuspended !== true).map((member)=>{
|
|
305
|
+
var _member_email, _member_displayName;
|
|
306
|
+
return {
|
|
307
|
+
id: String(member.$id),
|
|
308
|
+
email: String((_member_email = member.email) != null ? _member_email : '').trim().toLowerCase(),
|
|
309
|
+
name: String((_member_displayName = member.displayName) != null ? _member_displayName : '').trim()
|
|
310
|
+
};
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* The workspace's members as a lookup target: by id, email or display name,
|
|
315
|
+
* with names like an unresolved one offered — so a Salesforce report's
|
|
316
|
+
* "Contact Owner" (a full name) resolves as well as an address does.
|
|
317
|
+
*/ export function crmMembersTarget() {
|
|
318
|
+
return {
|
|
319
|
+
matchKeys: [
|
|
320
|
+
{
|
|
321
|
+
fieldId: 'email',
|
|
322
|
+
normalizer: 'email'
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
fieldId: 'name',
|
|
326
|
+
normalizer: 'caseless'
|
|
327
|
+
}
|
|
328
|
+
],
|
|
329
|
+
async lookup (ctx, requests) {
|
|
330
|
+
const members = await memberEntries(ctx.orgId);
|
|
331
|
+
const lookup = new Map();
|
|
332
|
+
const records = new Map();
|
|
333
|
+
for (const request of requests){
|
|
334
|
+
for (const value of request.values){
|
|
335
|
+
const found = members.filter((member)=>request.fieldId === 'id' ? member.id === value : request.fieldId === 'email' ? member.email === value.toLowerCase() : member.name.toLowerCase() === value.toLowerCase());
|
|
336
|
+
if (!found.length) continue;
|
|
337
|
+
lookup.set(matchLookupKey(request.fieldId, value), found.map((member)=>member.id));
|
|
338
|
+
for (const member of found)records.set(member.id, {
|
|
339
|
+
name: member.name || member.email,
|
|
340
|
+
email: member.email
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
lookup,
|
|
346
|
+
records
|
|
347
|
+
};
|
|
348
|
+
},
|
|
349
|
+
async suggest (ctx, request) {
|
|
350
|
+
const members = await memberEntries(ctx.orgId);
|
|
351
|
+
const candidates = members.flatMap((member)=>[
|
|
352
|
+
{
|
|
353
|
+
recordId: member.id,
|
|
354
|
+
label: member.email
|
|
355
|
+
},
|
|
356
|
+
...member.name ? [
|
|
357
|
+
{
|
|
358
|
+
recordId: member.id,
|
|
359
|
+
label: member.name
|
|
360
|
+
}
|
|
361
|
+
] : []
|
|
362
|
+
]);
|
|
363
|
+
return Object.fromEntries(request.values.map((value)=>[
|
|
364
|
+
value,
|
|
365
|
+
rankTransferLookupSuggestions(value, candidates)
|
|
366
|
+
]));
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
/** Member uid → email, for the owner columns of an export. */ export async function crmMemberEmails(orgId) {
|
|
371
|
+
return new Map((await memberEntries(orgId)).map((member)=>[
|
|
372
|
+
member.id,
|
|
373
|
+
member.email
|
|
374
|
+
]));
|
|
375
|
+
}
|
|
376
|
+
const FILTER_OPS = new Set([
|
|
377
|
+
'<',
|
|
378
|
+
'<=',
|
|
379
|
+
'==',
|
|
380
|
+
'!=',
|
|
381
|
+
'>=',
|
|
382
|
+
'>',
|
|
383
|
+
'array-contains',
|
|
384
|
+
'in',
|
|
385
|
+
'not-in',
|
|
386
|
+
'array-contains-any'
|
|
387
|
+
]);
|
|
388
|
+
/** A filter value as the list sent it: a date travels as `{ $date }`. */ function filterValue(value) {
|
|
389
|
+
if (value && typeof value === 'object' && !Array.isArray(value) && typeof value.$date === 'string') {
|
|
390
|
+
return Timestamp.fromDate(new Date(value.$date));
|
|
391
|
+
}
|
|
392
|
+
return Array.isArray(value) ? value.map(filterValue) : value;
|
|
393
|
+
}
|
|
394
|
+
/** The list's filter, read from an untrusted body, or the refusal. */ export function readExportFilter(raw) {
|
|
395
|
+
if (!raw) return null;
|
|
396
|
+
const filters = Array.isArray(raw['filters']) ? raw['filters'] : null;
|
|
397
|
+
const orderBy = raw['orderBy'];
|
|
398
|
+
if (!filters || !orderBy || typeof orderBy.path !== 'string') {
|
|
399
|
+
throw new TransferEngineError('invalid', 400, 'The list’s filter could not be read; export everything or a selection.');
|
|
400
|
+
}
|
|
401
|
+
return {
|
|
402
|
+
filters: filters.map((entry)=>{
|
|
403
|
+
const filter = entry;
|
|
404
|
+
if (typeof filter.path !== 'string' || !FILTER_OPS.has(String(filter.op))) {
|
|
405
|
+
throw new TransferEngineError('invalid', 400, 'The list’s filter could not be read; export everything or a selection.');
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
path: filter.path,
|
|
409
|
+
op: filter.op,
|
|
410
|
+
value: filterValue(filter.value)
|
|
411
|
+
};
|
|
412
|
+
}),
|
|
413
|
+
orderBy: {
|
|
414
|
+
path: orderBy.path,
|
|
415
|
+
direction: orderBy.direction === 'desc' ? 'desc' : 'asc'
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* The query an export reads: the list's filter, or every record the site
|
|
421
|
+
* (or the scoped reader) sees, in document order. A list filter already
|
|
422
|
+
* carries the reader's `visibleTo` clause when they are scoped, as the
|
|
423
|
+
* rules require of the list; a filter that lacks it gets one, when it has
|
|
424
|
+
* no other array clause, and is refused otherwise — so the count is exact
|
|
425
|
+
* and no record outside the reader's scope is ever read.
|
|
426
|
+
*/ export function crmExportQuery(env, collection, options) {
|
|
427
|
+
var _options_scopeTokens;
|
|
428
|
+
const filter = readExportFilter(options == null ? void 0 : options.filter);
|
|
429
|
+
const tokens = (options == null ? void 0 : (_options_scopeTokens = options.scopeTokens) == null ? void 0 : _options_scopeTokens.length) ? [
|
|
430
|
+
...options.scopeTokens
|
|
431
|
+
] : env.siteTokens;
|
|
432
|
+
if (filter) {
|
|
433
|
+
const scoped = filter.filters.some((entry)=>entry.path === 'visibleTo');
|
|
434
|
+
const array = filter.filters.some((entry)=>entry.op === 'array-contains' || entry.op === 'array-contains-any');
|
|
435
|
+
if (tokens && !scoped) {
|
|
436
|
+
if (array) {
|
|
437
|
+
throw new TransferEngineError('invalid', 400, 'This filter cannot be exported from here; export everything or a selection.');
|
|
438
|
+
}
|
|
439
|
+
return applyListQuery(collection.where('visibleTo', 'array-contains-any', tokens), filter);
|
|
440
|
+
}
|
|
441
|
+
return applyListQuery(collection, filter);
|
|
442
|
+
}
|
|
443
|
+
const base = tokens ? collection.where('visibleTo', 'array-contains-any', tokens) : collection;
|
|
444
|
+
return base.orderBy(FieldPath.documentId());
|
|
445
|
+
}
|
|
446
|
+
/** How many records an export with these options reads. */ export async function countCrmExport(env, collection, options, visible) {
|
|
447
|
+
var _data_count;
|
|
448
|
+
if (options.ids) {
|
|
449
|
+
let count = 0;
|
|
450
|
+
for(let at = 0; at < options.ids.length; at += EXPORT_PAGE){
|
|
451
|
+
const refs = options.ids.slice(at, at + EXPORT_PAGE).filter((id)=>id && !id.includes('/')).map((id)=>collection.doc(id));
|
|
452
|
+
if (!refs.length) continue;
|
|
453
|
+
for (const snapshot of (await env.firestore.getAll(...refs))){
|
|
454
|
+
var _snapshot_data;
|
|
455
|
+
if (snapshot.exists && visible((_snapshot_data = snapshot.data()) != null ? _snapshot_data : {})) count += 1;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return count;
|
|
459
|
+
}
|
|
460
|
+
return Number((_data_count = (await crmExportQuery(env, collection, options).count().get()).data().count) != null ? _data_count : 0);
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* One page of an export: the selection by id (in the order given), or the
|
|
464
|
+
* query's next page after the cursor. Every document is checked against the
|
|
465
|
+
* site's and the reader's tokens before it becomes a row.
|
|
466
|
+
*/ export async function readCrmExportPage(env, collection, cursor, options, visible, toRows) {
|
|
467
|
+
var _ref;
|
|
468
|
+
const size = Math.min((_ref = options == null ? void 0 : options.pageSize) != null ? _ref : EXPORT_PAGE, EXPORT_PAGE);
|
|
469
|
+
if (options == null ? void 0 : options.ids) {
|
|
470
|
+
const start = cursor ? Number(cursor) || 0 : 0;
|
|
471
|
+
const ids = options.ids.slice(start, start + size).filter((id)=>id && !id.includes('/'));
|
|
472
|
+
const snapshots = ids.length ? await env.firestore.getAll(...ids.map((id)=>collection.doc(id))) : [];
|
|
473
|
+
const docs = snapshots.filter((snapshot)=>{
|
|
474
|
+
var _snapshot_data;
|
|
475
|
+
return snapshot.exists && visible((_snapshot_data = snapshot.data()) != null ? _snapshot_data : {});
|
|
476
|
+
}).map((snapshot)=>{
|
|
477
|
+
var _snapshot_data;
|
|
478
|
+
return {
|
|
479
|
+
id: snapshot.id,
|
|
480
|
+
data: (_snapshot_data = snapshot.data()) != null ? _snapshot_data : {}
|
|
481
|
+
};
|
|
482
|
+
});
|
|
483
|
+
const next = start + size < options.ids.length ? String(start + size) : null;
|
|
484
|
+
return {
|
|
485
|
+
rows: await toRows(docs),
|
|
486
|
+
next
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
let query = crmExportQuery(env, collection, options).limit(size);
|
|
490
|
+
if (cursor) {
|
|
491
|
+
const after = await collection.doc(cursor).get();
|
|
492
|
+
if (after.exists) query = query.startAfter(after);
|
|
493
|
+
}
|
|
494
|
+
const snapshot = await query.get();
|
|
495
|
+
const docs = snapshot.docs.filter((doc)=>{
|
|
496
|
+
var _doc_data;
|
|
497
|
+
return visible((_doc_data = doc.data()) != null ? _doc_data : {});
|
|
498
|
+
}).map((doc)=>{
|
|
499
|
+
var _doc_data;
|
|
500
|
+
return {
|
|
501
|
+
id: doc.id,
|
|
502
|
+
data: (_doc_data = doc.data()) != null ? _doc_data : {}
|
|
503
|
+
};
|
|
504
|
+
});
|
|
505
|
+
const last = snapshot.docs[snapshot.docs.length - 1];
|
|
506
|
+
return {
|
|
507
|
+
rows: await toRows(docs),
|
|
508
|
+
next: snapshot.docs.length === size && last ? last.id : null
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Records by each requested value of one stored field, thirty to an `in`
|
|
513
|
+
* query; `fold` turns a requested value into the stored one. The answer is
|
|
514
|
+
* filed under the value AS REQUESTED, which is the key the engine asks by.
|
|
515
|
+
*/ export async function lookupByField(collection, request, storedField, fold, visible, into) {
|
|
516
|
+
const byStored = new Map();
|
|
517
|
+
for (const value of request.values){
|
|
518
|
+
var _byStored_get;
|
|
519
|
+
const stored = fold(value);
|
|
520
|
+
if (!stored) continue;
|
|
521
|
+
byStored.set(stored, [
|
|
522
|
+
...(_byStored_get = byStored.get(stored)) != null ? _byStored_get : [],
|
|
523
|
+
value
|
|
524
|
+
]);
|
|
525
|
+
}
|
|
526
|
+
const keys = [
|
|
527
|
+
...byStored.keys()
|
|
528
|
+
];
|
|
529
|
+
for(let at = 0; at < keys.length; at += IN_LIMIT){
|
|
530
|
+
const page = keys.slice(at, at + IN_LIMIT);
|
|
531
|
+
const snapshot = await collection.where(storedField, 'in', page).get();
|
|
532
|
+
for (const doc of snapshot.docs){
|
|
533
|
+
var _doc_data, _byStored_get1, _data_storedField;
|
|
534
|
+
const data = (_doc_data = doc.data()) != null ? _doc_data : {};
|
|
535
|
+
if (!visible(data)) continue;
|
|
536
|
+
into.docs.set(doc.id, data);
|
|
537
|
+
for (const value of (_byStored_get1 = byStored.get(String((_data_storedField = data[storedField]) != null ? _data_storedField : ''))) != null ? _byStored_get1 : []){
|
|
538
|
+
var _into_lookup_get;
|
|
539
|
+
const key = matchLookupKey(request.fieldId, value);
|
|
540
|
+
into.lookup.set(key, [
|
|
541
|
+
...new Set([
|
|
542
|
+
...(_into_lookup_get = into.lookup.get(key)) != null ? _into_lookup_get : [],
|
|
543
|
+
doc.id
|
|
544
|
+
])
|
|
545
|
+
]);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
/** Records by id, the ones the transfer may read. */ export async function lookupById(env, collection, request, visible, into) {
|
|
551
|
+
const ids = request.values.filter((id)=>id && !id.includes('/'));
|
|
552
|
+
for(let at = 0; at < ids.length; at += EXPORT_PAGE){
|
|
553
|
+
const page = ids.slice(at, at + EXPORT_PAGE);
|
|
554
|
+
const snapshots = await env.firestore.getAll(...page.map((id)=>collection.doc(id)));
|
|
555
|
+
for (const snapshot of snapshots){
|
|
556
|
+
const data = snapshot.data();
|
|
557
|
+
if (!snapshot.exists || !data || !visible(data)) continue;
|
|
558
|
+
into.docs.set(snapshot.id, data);
|
|
559
|
+
into.lookup.set(matchLookupKey(request.fieldId, snapshot.id), [
|
|
560
|
+
snapshot.id
|
|
561
|
+
]);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
/** A lookup answer from the documents found, each read into values by `read`. */ export function lookupResult(found, read) {
|
|
566
|
+
const records = new Map();
|
|
567
|
+
for (const [id, data] of found.docs)records.set(id, read(id, data));
|
|
568
|
+
return {
|
|
569
|
+
lookup: found.lookup,
|
|
570
|
+
records
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
/*==========================================
|
|
574
|
+
* VALUES
|
|
575
|
+
*=========================================*/ /** Epoch milliseconds from a stored timestamp (a Firestore `Timestamp`, a `Date` or a number), or `null`. */ export function storedMs(value) {
|
|
576
|
+
var _value_toDate;
|
|
577
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
578
|
+
if (value instanceof Date) return value.getTime();
|
|
579
|
+
const date = value == null ? void 0 : (_value_toDate = value.toDate) == null ? void 0 : _value_toDate.call(value);
|
|
580
|
+
return date ? date.getTime() : null;
|
|
581
|
+
}
|
|
582
|
+
/** An instant as the export writes it (ISO), or `null`. */ export function isoOf(value) {
|
|
583
|
+
const ms = storedMs(value);
|
|
584
|
+
return ms === null ? null : new Date(ms).toISOString();
|
|
585
|
+
}
|
|
586
|
+
/** A postal address as the six values `<prefix>Street` … `<prefix>Country`. */ export function addressValues(prefix, address) {
|
|
587
|
+
const stored = address && typeof address === 'object' ? address : {};
|
|
588
|
+
return Object.fromEntries(CRM_ADDRESS_PARTS.map((part)=>{
|
|
589
|
+
const value = stored[CRM_ADDRESS_PART_KEYS[part]];
|
|
590
|
+
return [
|
|
591
|
+
`${prefix}${part}`,
|
|
592
|
+
typeof value === 'string' && value ? value : null
|
|
593
|
+
];
|
|
594
|
+
}));
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* The address a row's parts make, over the one the record holds: a part
|
|
598
|
+
* the row names (blank clears it) replaces the stored part. `undefined`
|
|
599
|
+
* when the row names no part; `null` when nothing of the address is left.
|
|
600
|
+
*/ export function addressFromValues(prefix, values, stored) {
|
|
601
|
+
var _base_country, _base_line1, _base_line2, _base_city, _base_state, _base_postalCode;
|
|
602
|
+
const named = CRM_ADDRESS_PARTS.filter((part)=>`${prefix}${part}` in values);
|
|
603
|
+
if (!named.length) return undefined;
|
|
604
|
+
const base = stored && typeof stored === 'object' ? _extends({}, stored) : {};
|
|
605
|
+
for (const part of named){
|
|
606
|
+
const value = values[`${prefix}${part}`];
|
|
607
|
+
base[CRM_ADDRESS_PART_KEYS[part]] = typeof value === 'string' ? value.trim() : '';
|
|
608
|
+
}
|
|
609
|
+
const country = String((_base_country = base['country']) != null ? _base_country : '').trim();
|
|
610
|
+
return normalizeAddress({
|
|
611
|
+
line1: String((_base_line1 = base['line1']) != null ? _base_line1 : ''),
|
|
612
|
+
line2: String((_base_line2 = base['line2']) != null ? _base_line2 : ''),
|
|
613
|
+
city: String((_base_city = base['city']) != null ? _base_city : ''),
|
|
614
|
+
state: String((_base_state = base['state']) != null ? _base_state : ''),
|
|
615
|
+
postalCode: String((_base_postalCode = base['postalCode']) != null ? _base_postalCode : ''),
|
|
616
|
+
country: country.length === 2 ? country.toUpperCase() : country
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
/** A planned row's values: each changed field's new value. */ export function plannedValues(row) {
|
|
620
|
+
return Object.fromEntries(row.diff.map((change)=>[
|
|
621
|
+
change.fieldId,
|
|
622
|
+
change.after
|
|
623
|
+
]));
|
|
624
|
+
}
|
|
625
|
+
/** Only `keys` of `values`, each present (a missing one as `null`). */ export function pickValues(values, keys) {
|
|
626
|
+
return Object.fromEntries([
|
|
627
|
+
...keys
|
|
628
|
+
].map((key)=>{
|
|
629
|
+
var _values_key;
|
|
630
|
+
return [
|
|
631
|
+
key,
|
|
632
|
+
(_values_key = values[key]) != null ? _values_key : null
|
|
633
|
+
];
|
|
634
|
+
}));
|
|
635
|
+
}
|
|
636
|
+
/** A text value, trimmed, or `''`. */ export function textOf(value) {
|
|
637
|
+
return value === null || value === undefined ? '' : String(value).trim();
|
|
638
|
+
}
|
|
639
|
+
/** A lookup cell's display key, for caching records a chunk creates by name. */ export function nameKey(value) {
|
|
640
|
+
return transferLookupKey(value);
|
|
641
|
+
}
|
|
642
|
+
/*------------------------------------------
|
|
643
|
+
* Custom values
|
|
644
|
+
*-----------------------------------------*/ /** The custom key a `custom:<key>` field id names, or `null`. */ export function customKeyOf(fieldId) {
|
|
645
|
+
return fieldId.startsWith('custom:') ? fieldId.slice('custom:'.length) : null;
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* A stored custom value as the file reads it: a date (stored as epoch
|
|
649
|
+
* milliseconds) as its day, `YYYY-MM-DD`; anything else as stored.
|
|
650
|
+
*/ export function customTransferValue(definition, value) {
|
|
651
|
+
if (value === null || value === undefined) return null;
|
|
652
|
+
if ((definition == null ? void 0 : definition.type) === 'date') {
|
|
653
|
+
const ms = storedMs(value);
|
|
654
|
+
return ms === null ? null : new Date(ms).toISOString().slice(0, 10);
|
|
655
|
+
}
|
|
656
|
+
return value;
|
|
657
|
+
}
|
|
658
|
+
/** Every custom field a record holds, as `custom:<key>` values. */ export function customTransferValues(definitions, stored) {
|
|
659
|
+
const custom = stored && typeof stored === 'object' ? stored : {};
|
|
660
|
+
return Object.fromEntries(definitions.map((definition)=>[
|
|
661
|
+
`custom:${definition.key}`,
|
|
662
|
+
customTransferValue(definition, custom[definition.key])
|
|
663
|
+
]));
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* The custom values a row writes, judged by the CRM's own reader
|
|
667
|
+
* (`readCrmCustomInput`): a blank clears (`null`), a date is read from its
|
|
668
|
+
* day. Answers the values, or the first refusal.
|
|
669
|
+
*/ export function customWriteValues(values, definitions, object) {
|
|
670
|
+
var _Object_values_;
|
|
671
|
+
const raw = {};
|
|
672
|
+
for (const [fieldId, value] of Object.entries(values)){
|
|
673
|
+
const key = customKeyOf(fieldId);
|
|
674
|
+
if (key) raw[key] = value === undefined || value === '' ? null : value;
|
|
675
|
+
}
|
|
676
|
+
if (!Object.keys(raw).length) return {
|
|
677
|
+
values: {}
|
|
678
|
+
};
|
|
679
|
+
const judged = readCrmCustomInput(raw, definitions, object);
|
|
680
|
+
if ('errors' in judged) return {
|
|
681
|
+
error: (_Object_values_ = Object.values(judged.errors)[0]) != null ? _Object_values_ : 'A custom value could not be saved.'
|
|
682
|
+
};
|
|
683
|
+
return {
|
|
684
|
+
values: judged.values
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
/*==========================================
|
|
688
|
+
* PLANS — values a plugin rule holds back
|
|
689
|
+
*=========================================*/ /**
|
|
690
|
+
* Removes the changes `decide` refuses from a plan, as a locked rule's: the
|
|
691
|
+
* field is listed in the row's `heldBack`, the row gains a `lockedRule`
|
|
692
|
+
* warning (acknowledged before Apply), and an update left with nothing to
|
|
693
|
+
* write becomes `unchanged`. For a rule no field policy can say — a stage
|
|
694
|
+
* that only moves forward, a flag a file may set and never clear.
|
|
695
|
+
*/ export function holdBackChanges(plan, decide) {
|
|
696
|
+
const warnings = new Map(plan.warnings.map((warning)=>[
|
|
697
|
+
warning.class,
|
|
698
|
+
_extends({}, warning)
|
|
699
|
+
]));
|
|
700
|
+
const rows = plan.rows.map((row)=>{
|
|
701
|
+
var _warnings_get;
|
|
702
|
+
if (row.verdict !== 'update' && row.verdict !== 'create') return row;
|
|
703
|
+
const held = [];
|
|
704
|
+
const diff = row.diff.filter((change)=>{
|
|
705
|
+
const reason = decide(row, change);
|
|
706
|
+
if (!reason) return true;
|
|
707
|
+
held.push({
|
|
708
|
+
fieldId: change.fieldId,
|
|
709
|
+
reason,
|
|
710
|
+
value: change.after
|
|
711
|
+
});
|
|
712
|
+
return false;
|
|
713
|
+
});
|
|
714
|
+
if (!held.length) return row;
|
|
715
|
+
const warning = (_warnings_get = warnings.get('lockedRule')) != null ? _warnings_get : {
|
|
716
|
+
class: 'lockedRule',
|
|
717
|
+
count: 0,
|
|
718
|
+
rows: 0,
|
|
719
|
+
fieldIds: [],
|
|
720
|
+
samples: [],
|
|
721
|
+
requiresAcknowledgement: true
|
|
722
|
+
};
|
|
723
|
+
warning.rows += 1;
|
|
724
|
+
for (const entry of held){
|
|
725
|
+
warning.count += 1;
|
|
726
|
+
if (!warning.fieldIds.includes(entry.fieldId)) warning.fieldIds = [
|
|
727
|
+
...warning.fieldIds,
|
|
728
|
+
entry.fieldId
|
|
729
|
+
];
|
|
730
|
+
if (warning.samples.length < 5) {
|
|
731
|
+
warning.samples = [
|
|
732
|
+
...warning.samples,
|
|
733
|
+
{
|
|
734
|
+
row: row.index,
|
|
735
|
+
fieldId: entry.fieldId,
|
|
736
|
+
value: textOf(entry.value),
|
|
737
|
+
detail: entry.reason
|
|
738
|
+
}
|
|
739
|
+
];
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
warnings.set('lockedRule', warning);
|
|
743
|
+
const verdict = row.verdict === 'update' && !diff.length ? 'unchanged' : row.verdict;
|
|
744
|
+
return _extends({}, row, {
|
|
745
|
+
verdict,
|
|
746
|
+
diff,
|
|
747
|
+
heldBack: [
|
|
748
|
+
...new Set([
|
|
749
|
+
...row.heldBack,
|
|
750
|
+
...held.map((entry)=>entry.fieldId)
|
|
751
|
+
])
|
|
752
|
+
],
|
|
753
|
+
warnings: [
|
|
754
|
+
...new Set([
|
|
755
|
+
...row.warnings,
|
|
756
|
+
'lockedRule'
|
|
757
|
+
])
|
|
758
|
+
]
|
|
759
|
+
});
|
|
760
|
+
});
|
|
761
|
+
const summary = {
|
|
762
|
+
create: 0,
|
|
763
|
+
update: 0,
|
|
764
|
+
unchanged: 0,
|
|
765
|
+
skip: 0,
|
|
766
|
+
fail: 0,
|
|
767
|
+
total: rows.length
|
|
768
|
+
};
|
|
769
|
+
for (const row of rows)summary[row.verdict] += 1;
|
|
770
|
+
const list = plan.warnings.map((warning)=>{
|
|
771
|
+
var _warnings_get;
|
|
772
|
+
return (_warnings_get = warnings.get(warning.class)) != null ? _warnings_get : warning;
|
|
773
|
+
});
|
|
774
|
+
const locked = warnings.get('lockedRule');
|
|
775
|
+
if (locked && !plan.warnings.some((warning)=>warning.class === 'lockedRule')) list.push(locked);
|
|
776
|
+
return {
|
|
777
|
+
rows,
|
|
778
|
+
summary,
|
|
779
|
+
warnings: list,
|
|
780
|
+
acknowledgementsRequired: [
|
|
781
|
+
...new Set([
|
|
782
|
+
...plan.acknowledgementsRequired,
|
|
783
|
+
...locked ? [
|
|
784
|
+
'lockedRule'
|
|
785
|
+
] : []
|
|
786
|
+
])
|
|
787
|
+
]
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
/*==========================================
|
|
791
|
+
* WRITING
|
|
792
|
+
*=========================================*/ /**
|
|
793
|
+
* `write` over `items`, {@link APPLY_CONCURRENCY} at a time, starting an
|
|
794
|
+
* item only while the chunk's budget lasts — the engine resumes the chunk
|
|
795
|
+
* at the next call for whatever is left.
|
|
796
|
+
*/ export async function eachWithinBudget(items, timeLeftMs, write) {
|
|
797
|
+
let next = 0;
|
|
798
|
+
const worker = async ()=>{
|
|
799
|
+
while(next < items.length){
|
|
800
|
+
if (timeLeftMs() < APPLY_ROW_BUDGET_MS) return;
|
|
801
|
+
const item = items[next];
|
|
802
|
+
next += 1;
|
|
803
|
+
await write(item);
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
await Promise.all(Array.from({
|
|
807
|
+
length: Math.min(APPLY_CONCURRENCY, items.length)
|
|
808
|
+
}, worker));
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* The CRM records band for the records one apply call creates beside the
|
|
812
|
+
* rows' own (a company a contact's company column names): counted once,
|
|
813
|
+
* then each create admitted from that tally. A plan with an overage rate
|
|
814
|
+
* always admits.
|
|
815
|
+
*/ export function crmRecordsRoom(env) {
|
|
816
|
+
let counted = null;
|
|
817
|
+
let created = 0;
|
|
818
|
+
return async ()=>{
|
|
819
|
+
counted != null ? counted : counted = crmRecordsQuotaForOrg(env.org, env.orgRef);
|
|
820
|
+
const { crmRecordsCount } = await counted;
|
|
821
|
+
if (!checkCrmRecordsQuota(env.org, crmRecordsCount + created).allowed) return false;
|
|
822
|
+
created += 1;
|
|
823
|
+
return true;
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
/** A thrown write as the sentence a row's result carries. */ export function failureMessage(error) {
|
|
827
|
+
if (error instanceof TransferEngineError) return error.message;
|
|
828
|
+
return 'The record could not be saved.';
|
|
829
|
+
}
|
|
830
|
+
export { TransferEngineError };
|
|
831
|
+
|
|
832
|
+
//# sourceMappingURL=common.js.map
|