@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.
- 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-next-activity-column.js +1 -1
- package/src/lib/components/crm-next-activity-column.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/pipeline-card.js +2 -1
- package/src/lib/components/reports/pipeline-card.js.map +1 -1
- 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 +97 -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 +17 -2
- 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-next-activity.d.ts +107 -0
- package/src/lib/model/crm-next-activity.js +140 -0
- package/src/lib/model/crm-next-activity.js.map +1 -0
- package/src/lib/model/crm-recipes.d.ts +40 -0
- package/src/lib/model/crm-recipes.js +259 -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/crm-task-reminders.d.ts +152 -0
- package/src/lib/model/crm-task-reminders.js +161 -0
- package/src/lib/model/crm-task-reminders.js.map +1 -0
- 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/next-activity.d.ts +1 -1
- package/src/lib/model/next-activity.js.map +1 -1
- 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 +78 -34
- 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 +188 -0
- package/src/lib/server/assign-contact-owner.js +446 -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 +140 -0
- package/src/lib/server/automation-steps.js +669 -0
- package/src/lib/server/automation-steps.js.map +1 -0
- package/src/lib/server/capture-contact.d.ts +17 -0
- package/src/lib/server/capture-contact.js +95 -26
- 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-email-activity.d.ts +118 -0
- package/src/lib/server/crm-email-activity.js +148 -0
- package/src/lib/server/crm-email-activity.js.map +1 -0
- package/src/lib/server/crm-inbound-email.js +1 -1
- package/src/lib/server/crm-inbound-email.js.map +1 -1
- package/src/lib/server/crm-next-activity.d.ts +74 -0
- package/src/lib/server/crm-next-activity.js +194 -0
- package/src/lib/server/crm-next-activity.js.map +1 -0
- 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/email-send.js +2 -1
- package/src/lib/server/email-send.js.map +1 -1
- 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 +23 -5
- package/src/lib/server/merge-contacts.js.map +1 -1
- package/src/lib/server/next-activity-routes.js +2 -1
- package/src/lib/server/next-activity-routes.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 +22 -8
- 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 +40 -3
- 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-reminders-route.js +2 -1
- package/src/lib/server/task-reminders-route.js.map +1 -1
- package/src/lib/server/task-routes.js +33 -17
- 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
|
@@ -25,14 +25,23 @@ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_wi
|
|
|
25
25
|
* a domain already held is a `409 company_exists` naming the first — the
|
|
26
26
|
* contact create's own rule for a second row on one email — and `?domain=`
|
|
27
27
|
* is the lookup a sync starts with.
|
|
28
|
+
*
|
|
29
|
+
* Salesforce's Account fields (AGL-3514) ride the same object: Type,
|
|
30
|
+
* Industry, Rating, Ownership and Account Source are labels of the org's
|
|
31
|
+
* lists — any other value is a 400 naming what the list allows, and the
|
|
32
|
+
* value a company already holds is kept — the rest are read through
|
|
33
|
+
* `readCrmCompanyAccountFields`, and `parentCompanyId` names another
|
|
34
|
+
* company of the organization that is not this one or below it.
|
|
28
35
|
*/ import { nameSearchFields } from "@aglyn/aglyn/app-utils/name-search";
|
|
29
|
-
import { CRM_COLLECTIONS, CRM_MEDIA_IDS_MAX, createResourceUid, crmNewRecordListFields, normalizeAddress, normalizeCompanyDomain, normalizeCrmMediaIds, normalizePhone } from "@aglyn/aglyn/server";
|
|
36
|
+
import { CRM_COLLECTIONS, CRM_COMPANY_ACCOUNT_FIELDS, CRM_COMPANY_PICKLIST_FIELDS, CRM_MEDIA_IDS_MAX, createResourceUid, crmCompanyParentId, crmCompanyParentRefusal, crmNewRecordListFields, judgeCrmCompanyPicklists, normalizeAddress, normalizeCompanyDomain, normalizeCrmMediaIds, normalizePhone, readCrmCompanyAccountFields } from "@aglyn/aglyn/server";
|
|
37
|
+
import { detachChildCompanies } from "../company-children.js";
|
|
38
|
+
import { readCrmPicklist } from "../read-picklist.js";
|
|
30
39
|
import { apiJson, ApiErrors, restampCrmListFieldsAt } from "@aglyn/tenant-data-admin";
|
|
31
40
|
import { Timestamp } from "firebase-admin/firestore";
|
|
32
41
|
import { claimWrite, readJsonBody, requireScope } from "@aglyn/tenant-data-admin/server/api-v1-kit";
|
|
33
42
|
import { CRM_LABEL_MAX, CRM_TEXT_MAX, CRM_TITLE_MAX, createPayload, crmCollection, crmCreateStamp, crmCustomUpdate, crmCustomView, crmRecordsBandRefusal, crmTimes, crmValidationFailed, isoFromMs, listCrm, memberError, readCrmCustomBody, readCrmSite, readEqualityFilters, readOptionalText, refuseUnknownKeys, updatePayload } from "./crm-shared.js";
|
|
34
43
|
/** The company object as published. Every writable field appears here. */ function companyView(doc) {
|
|
35
|
-
var _doc_data, _data_name, _data_domain, _data_website, _data_phone, _data_address, _data_industry, _data_ownerUid, _data_notes, _data_hostId;
|
|
44
|
+
var _doc_data, _data_name, _data_domain, _data_website, _data_phone, _data_address, _data_industry, _data_type, _data_rating, _data_ownership, _data_accountSource, _data_currency, _data_fax, _data_accountNumber, _data_site, _data_tickerSymbol, _data_sicCode, _data_shippingAddress, _data_ownerUid, _data_notes, _data_hostId;
|
|
36
45
|
const data = (_doc_data = doc.data()) != null ? _doc_data : {};
|
|
37
46
|
return _extends({
|
|
38
47
|
id: doc.id,
|
|
@@ -41,8 +50,25 @@ import { CRM_LABEL_MAX, CRM_TEXT_MAX, CRM_TITLE_MAX, createPayload, crmCollectio
|
|
|
41
50
|
domain: (_data_domain = data.domain) != null ? _data_domain : null,
|
|
42
51
|
website: (_data_website = data.website) != null ? _data_website : null,
|
|
43
52
|
phone: (_data_phone = data.phone) != null ? _data_phone : null,
|
|
53
|
+
// The billing address, under the name it always had.
|
|
44
54
|
address: (_data_address = data.address) != null ? _data_address : null,
|
|
45
55
|
industry: (_data_industry = data.industry) != null ? _data_industry : null,
|
|
56
|
+
// Salesforce's Account fields (AGL-3514).
|
|
57
|
+
type: (_data_type = data.type) != null ? _data_type : null,
|
|
58
|
+
rating: (_data_rating = data.rating) != null ? _data_rating : null,
|
|
59
|
+
ownership: (_data_ownership = data.ownership) != null ? _data_ownership : null,
|
|
60
|
+
accountSource: (_data_accountSource = data.accountSource) != null ? _data_accountSource : null,
|
|
61
|
+
annualRevenueCents: typeof data.annualRevenueCents === 'number' ? data.annualRevenueCents : null,
|
|
62
|
+
// `'usd'` when absent, as a deal's is.
|
|
63
|
+
currency: (_data_currency = data.currency) != null ? _data_currency : 'usd',
|
|
64
|
+
numberOfEmployees: typeof data.numberOfEmployees === 'number' ? data.numberOfEmployees : null,
|
|
65
|
+
fax: (_data_fax = data.fax) != null ? _data_fax : null,
|
|
66
|
+
accountNumber: (_data_accountNumber = data.accountNumber) != null ? _data_accountNumber : null,
|
|
67
|
+
site: (_data_site = data.site) != null ? _data_site : null,
|
|
68
|
+
tickerSymbol: (_data_tickerSymbol = data.tickerSymbol) != null ? _data_tickerSymbol : null,
|
|
69
|
+
sicCode: (_data_sicCode = data.sicCode) != null ? _data_sicCode : null,
|
|
70
|
+
shippingAddress: (_data_shippingAddress = data.shippingAddress) != null ? _data_shippingAddress : null,
|
|
71
|
+
parentCompanyId: crmCompanyParentId(data.parentCompanyId),
|
|
46
72
|
ownerUid: (_data_ownerUid = data.ownerUid) != null ? _data_ownerUid : null,
|
|
47
73
|
notes: (_data_notes = data.notes) != null ? _data_notes : null,
|
|
48
74
|
// The org's company custom fields, keyed by field key (AGL-2661).
|
|
@@ -64,7 +90,11 @@ const COMPANY_WRITABLE = new Set([
|
|
|
64
90
|
'ownerUid',
|
|
65
91
|
'notes',
|
|
66
92
|
'custom',
|
|
67
|
-
'mediaIds'
|
|
93
|
+
'mediaIds',
|
|
94
|
+
// Salesforce's Account fields (AGL-3514).
|
|
95
|
+
...CRM_COMPANY_PICKLIST_FIELDS.map((entry)=>entry.field),
|
|
96
|
+
...CRM_COMPANY_ACCOUNT_FIELDS,
|
|
97
|
+
'parentCompanyId'
|
|
68
98
|
]);
|
|
69
99
|
/**
|
|
70
100
|
* The writable half of a company, validated. `partial` separates PATCH from
|
|
@@ -79,6 +109,7 @@ const COMPANY_WRITABLE = new Set([
|
|
|
79
109
|
*/ function readCompanyInput(body, { partial }) {
|
|
80
110
|
const errors = {};
|
|
81
111
|
const values = {};
|
|
112
|
+
const picklists = {};
|
|
82
113
|
const allowed = new Set(COMPANY_WRITABLE);
|
|
83
114
|
if (!partial) allowed.add('consentSiteId');
|
|
84
115
|
refuseUnknownKeys(body, allowed, 'company', errors);
|
|
@@ -146,8 +177,16 @@ const COMPANY_WRITABLE = new Set([
|
|
|
146
177
|
values.address = normalizeAddress(body.address);
|
|
147
178
|
}
|
|
148
179
|
}
|
|
149
|
-
const
|
|
150
|
-
|
|
180
|
+
for (const { field } of CRM_COMPANY_PICKLIST_FIELDS){
|
|
181
|
+
const label = readOptionalText(body, field, CRM_LABEL_MAX, errors);
|
|
182
|
+
if (label !== undefined) picklists[field] = label;
|
|
183
|
+
}
|
|
184
|
+
const account = readCrmCompanyAccountFields(body);
|
|
185
|
+
Object.assign(errors, account.errors);
|
|
186
|
+
values.account = account.values;
|
|
187
|
+
const parentCompanyId = readOptionalText(body, 'parentCompanyId', CRM_LABEL_MAX, errors);
|
|
188
|
+
if (parentCompanyId && parentCompanyId.includes('/')) errors.parentCompanyId = 'No such company';
|
|
189
|
+
else if (parentCompanyId !== undefined) values.parentCompanyId = parentCompanyId;
|
|
151
190
|
const ownerUid = readOptionalText(body, 'ownerUid', CRM_LABEL_MAX, errors);
|
|
152
191
|
if (ownerUid !== undefined) values.ownerUid = ownerUid;
|
|
153
192
|
const notes = readOptionalText(body, 'notes', CRM_TEXT_MAX, errors);
|
|
@@ -162,7 +201,48 @@ const COMPANY_WRITABLE = new Set([
|
|
|
162
201
|
return Object.keys(errors).length ? {
|
|
163
202
|
errors
|
|
164
203
|
} : {
|
|
165
|
-
values
|
|
204
|
+
values,
|
|
205
|
+
picklists
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/** The org's list behind every company picklist field the body names. */ async function readNamedPicklists(ctx, named, created) {
|
|
209
|
+
// A create starts every field from its list's default, so it reads them all.
|
|
210
|
+
const ids = [
|
|
211
|
+
...new Set(CRM_COMPANY_PICKLIST_FIELDS.filter((entry)=>created || named[entry.field] !== undefined).map((entry)=>entry.picklistId))
|
|
212
|
+
];
|
|
213
|
+
const lists = await Promise.all(ids.map((id)=>readCrmPicklist(ctx.firestore, ctx.orgId, id)));
|
|
214
|
+
return Object.fromEntries(ids.map((id, at)=>[
|
|
215
|
+
id,
|
|
216
|
+
lists[at]
|
|
217
|
+
]));
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* The picklist values and the parent a write stores, or the 400's fields:
|
|
221
|
+
* each label judged against its list with the company's `current` value
|
|
222
|
+
* kept, and a parent that is this company, one below it, or none the
|
|
223
|
+
* organization holds refused by name.
|
|
224
|
+
*/ async function judgeCompanyReferences(ctx, collection, input, options) {
|
|
225
|
+
const created = options.companyId === null;
|
|
226
|
+
const lists = await readNamedPicklists(ctx, input.picklists, created);
|
|
227
|
+
const judged = judgeCrmCompanyPicklists(lists, input.picklists, {
|
|
228
|
+
current: options.current,
|
|
229
|
+
created
|
|
230
|
+
});
|
|
231
|
+
const errors = _extends({}, judged.errors);
|
|
232
|
+
const parentId = input.parentCompanyId;
|
|
233
|
+
if (parentId && parentId !== crmCompanyParentId(options.current['parentCompanyId'])) {
|
|
234
|
+
const refusal = await crmCompanyParentRefusal(options.companyId, parentId, async (id)=>{
|
|
235
|
+
const snapshot = await collection.doc(id).get();
|
|
236
|
+
return snapshot.exists ? {
|
|
237
|
+
parentCompanyId: crmCompanyParentId(snapshot.get('parentCompanyId'))
|
|
238
|
+
} : null;
|
|
239
|
+
});
|
|
240
|
+
if (refusal) errors.parentCompanyId = refusal;
|
|
241
|
+
}
|
|
242
|
+
return Object.keys(errors).length ? {
|
|
243
|
+
errors
|
|
244
|
+
} : {
|
|
245
|
+
picklists: judged.values
|
|
166
246
|
};
|
|
167
247
|
}
|
|
168
248
|
/**
|
|
@@ -185,13 +265,24 @@ const COMPANY_WRITABLE = new Set([
|
|
|
185
265
|
if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors);
|
|
186
266
|
const customValues = custom && 'values' in custom ? custom.values : {};
|
|
187
267
|
const collection = crmCollection(ctx, CRM_COLLECTIONS.companies);
|
|
268
|
+
// The org's lists and the parent (AGL-3514), above the claim with the
|
|
269
|
+
// other deterministic 400s.
|
|
270
|
+
const references = await judgeCompanyReferences(ctx, collection, {
|
|
271
|
+
picklists: parsed.picklists,
|
|
272
|
+
parentCompanyId: parsed.values.parentCompanyId
|
|
273
|
+
}, {
|
|
274
|
+
companyId: null,
|
|
275
|
+
current: {}
|
|
276
|
+
});
|
|
277
|
+
if ('errors' in references) return crmValidationFailed(ctx, 'company', references.errors);
|
|
188
278
|
const claimed = await claimWrite(ctx, '*', request.headers.get('Idempotency-Key'), 'companies');
|
|
189
279
|
if ('replay' in claimed) return claimed.replay;
|
|
190
280
|
const { claim } = claimed;
|
|
191
281
|
try {
|
|
192
|
-
const _parsed_values = parsed.values, { name, domain } = _parsed_values, rest = _object_without_properties_loose(_parsed_values, [
|
|
282
|
+
const _parsed_values = parsed.values, { name, domain, account } = _parsed_values, rest = _object_without_properties_loose(_parsed_values, [
|
|
193
283
|
"name",
|
|
194
|
-
"domain"
|
|
284
|
+
"domain",
|
|
285
|
+
"account"
|
|
195
286
|
]);
|
|
196
287
|
if (domain) {
|
|
197
288
|
const existing = await collection.where('domain', '==', domain).limit(1).get();
|
|
@@ -215,7 +306,7 @@ const COMPANY_WRITABLE = new Set([
|
|
|
215
306
|
const id = createResourceUid();
|
|
216
307
|
const record = _extends({}, nameSearchFields(name != null ? name : ''), createPayload(_extends({
|
|
217
308
|
domain
|
|
218
|
-
}, rest)), Object.keys(customValues).length ? {
|
|
309
|
+
}, rest, references.picklists, account)), Object.keys(customValues).length ? {
|
|
219
310
|
custom: createPayload(customValues)
|
|
220
311
|
} : {}, crmCreateStamp(ctx, site.siteId));
|
|
221
312
|
// What the console's Companies list searches and filters by (AGL-3321).
|
|
@@ -233,6 +324,7 @@ const COMPANY_WRITABLE = new Set([
|
|
|
233
324
|
}
|
|
234
325
|
}
|
|
235
326
|
/** `PATCH /v1/companies/{id}` — no key, for `updateContact`'s reason. */ async function updateCompany(request, ctx, ref) {
|
|
327
|
+
var _snap_data;
|
|
236
328
|
const body = await readJsonBody(request);
|
|
237
329
|
const parsed = readCompanyInput(body, {
|
|
238
330
|
partial: true
|
|
@@ -249,9 +341,18 @@ const COMPANY_WRITABLE = new Set([
|
|
|
249
341
|
if (Object.keys(owner).length) return crmValidationFailed(ctx, 'company', owner);
|
|
250
342
|
const custom = await readCrmCustomBody(ctx, body, 'company');
|
|
251
343
|
if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors);
|
|
252
|
-
const
|
|
344
|
+
const references = await judgeCompanyReferences(ctx, ref.parent, {
|
|
345
|
+
picklists: parsed.picklists,
|
|
346
|
+
parentCompanyId: parsed.values.parentCompanyId
|
|
347
|
+
}, {
|
|
348
|
+
companyId: ref.id,
|
|
349
|
+
current: (_snap_data = snap.data()) != null ? _snap_data : {}
|
|
350
|
+
});
|
|
351
|
+
if ('errors' in references) return crmValidationFailed(ctx, 'company', references.errors);
|
|
352
|
+
const _parsed_values = parsed.values, { name, domain, account } = _parsed_values, rest = _object_without_properties_loose(_parsed_values, [
|
|
253
353
|
"name",
|
|
254
|
-
"domain"
|
|
354
|
+
"domain",
|
|
355
|
+
"account"
|
|
255
356
|
]);
|
|
256
357
|
if (domain && domain !== snap.get('domain')) {
|
|
257
358
|
const existing = await ref.parent.where('domain', '==', domain).limit(1).get();
|
|
@@ -265,13 +366,14 @@ const COMPANY_WRITABLE = new Set([
|
|
|
265
366
|
}
|
|
266
367
|
const update = _extends({}, name !== undefined ? nameSearchFields(name) : {}, updatePayload(_extends({
|
|
267
368
|
domain
|
|
268
|
-
}, rest)), custom && 'values' in custom ? crmCustomUpdate(custom.values) : {});
|
|
369
|
+
}, rest, references.picklists, account)), custom && 'values' in custom ? crmCustomUpdate(custom.values) : {});
|
|
269
370
|
// An empty body is a no-op answered with the current company.
|
|
270
371
|
if (Object.keys(update).length > 0) {
|
|
271
372
|
await ref.update(_extends({}, update, {
|
|
272
373
|
updatedAt: Timestamp.now()
|
|
273
374
|
}));
|
|
274
|
-
// What the console's Companies list searches (AGL-3321)
|
|
375
|
+
// What the console's Companies list searches (AGL-3321) and filters
|
|
376
|
+
// by (AGL-3514).
|
|
275
377
|
await restampCrmListFieldsAt(ref, 'companies');
|
|
276
378
|
}
|
|
277
379
|
return apiJson(companyView(await ref.get()), {
|
|
@@ -282,7 +384,8 @@ const COMPANY_WRITABLE = new Set([
|
|
|
282
384
|
* `DELETE /v1/companies/{id}` — the company alone. The deals, tasks and
|
|
283
385
|
* activities filed against it keep their `companyId`; they are records of
|
|
284
386
|
* their own, and a delete that cascaded through them would erase a sales
|
|
285
|
-
* history because somebody removed a duplicate account.
|
|
387
|
+
* history because somebody removed a duplicate account. The companies
|
|
388
|
+
* under it keep everything but their `parentCompanyId` (AGL-3514).
|
|
286
389
|
*/ async function deleteCompany(request, ctx, ref) {
|
|
287
390
|
const claimed = await claimWrite(ctx, '*', request.headers.get('Idempotency-Key'), 'company-deletes');
|
|
288
391
|
if ('replay' in claimed) return claimed.replay;
|
|
@@ -296,6 +399,12 @@ const COMPANY_WRITABLE = new Set([
|
|
|
296
399
|
headers: ctx.headers
|
|
297
400
|
});
|
|
298
401
|
}
|
|
402
|
+
// The companies under it stand on their own (AGL-3514): their parent is
|
|
403
|
+
// cleared, a batch at a time, before it goes.
|
|
404
|
+
for(;;){
|
|
405
|
+
const pass = await detachChildCompanies(ctx.firestore, ref.parent, ref.id);
|
|
406
|
+
if (!pass.moreRemain) break;
|
|
407
|
+
}
|
|
299
408
|
await ref.delete();
|
|
300
409
|
const view = {
|
|
301
410
|
id: ref.id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/server/api-v1/crm-companies.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * `/v1/companies` (AGL-2606) — the organizations behind the people.\n *\n * A company is keyed, in practice, by its domain: two contacts at\n * `example.com` work for one company, and the console's auto-association\n * (`companyDomainForEmail`) files them under it by that string. So the\n * domain is normalized exactly as the console stores it, a second company on\n * a domain already held is a `409 company_exists` naming the first — the\n * contact create's own rule for a second row on one email — and `?domain=`\n * is the lookup a sync starts with.\n */\nimport { nameSearchFields } from '@aglyn/aglyn/app-utils/name-search'\nimport {\n CRM_COLLECTIONS,\n CRM_MEDIA_IDS_MAX,\n createResourceUid,\n crmNewRecordListFields,\n normalizeAddress,\n normalizeCompanyDomain,\n normalizeCrmMediaIds,\n normalizePhone,\n} from '@aglyn/aglyn/server'\nimport { apiJson, ApiErrors, restampCrmListFieldsAt } from '@aglyn/tenant-data-admin'\nimport { Timestamp } from 'firebase-admin/firestore'\nimport {\n type ApiV1Context,\n claimWrite,\n readJsonBody,\n requireScope,\n} from '@aglyn/tenant-data-admin/server/api-v1-kit'\nimport {\n type Clearable,\n CRM_LABEL_MAX,\n CRM_TEXT_MAX,\n CRM_TITLE_MAX,\n createPayload,\n crmCollection,\n crmCreateStamp,\n crmCustomUpdate,\n crmCustomView,\n crmRecordsBandRefusal,\n crmTimes,\n crmValidationFailed,\n isoFromMs,\n listCrm,\n memberError,\n readCrmCustomBody,\n readCrmSite,\n readEqualityFilters,\n readOptionalText,\n refuseUnknownKeys,\n updatePayload,\n} from './crm-shared'\n\n/** The company object as published. Every writable field appears here. */\nfunction companyView(doc: FirebaseFirestore.DocumentSnapshot) {\n const data = doc.data() ?? {}\n return {\n id: doc.id,\n object: 'company',\n name: data.name ?? null,\n domain: data.domain ?? null,\n website: data.website ?? null,\n phone: data.phone ?? null,\n address: data.address ?? null,\n industry: data.industry ?? null,\n ownerUid: data.ownerUid ?? null,\n notes: data.notes ?? null,\n // The org's company custom fields, keyed by field key (AGL-2661).\n custom: crmCustomView(data),\n // When the earliest open task against the company is due — see\n // `CrmDeal.nextTaskAtMs`. Read-only: the tasks resource maintains it.\n nextTaskAt: isoFromMs(data.nextTaskAtMs),\n mediaIds: normalizeCrmMediaIds(data.mediaIds),\n siteId: data.hostId ?? null,\n ...crmTimes(data),\n }\n}\n\nconst COMPANY_WRITABLE = new Set([\n 'name',\n 'domain',\n 'website',\n 'phone',\n 'address',\n 'industry',\n 'ownerUid',\n 'notes',\n 'custom',\n 'mediaIds',\n])\n\ninterface CompanyInput {\n name?: string\n domain?: Clearable<string>\n website?: Clearable<string>\n phone?: Clearable<string>\n address?: Clearable<ReturnType<typeof normalizeAddress>>\n industry?: Clearable<string>\n ownerUid?: Clearable<string>\n notes?: Clearable<string>\n /** Org-library files attached to the company (AGL-2662), by media id. */\n mediaIds?: string[]\n}\n\n/**\n * The writable half of a company, validated. `partial` separates PATCH from\n * POST as every reader in this API does: a create needs a name, an update\n * may send one field alone. Unknown keys are named, never dropped.\n *\n * `domain` and `phone` go through the console's own normalizers so the API\n * cannot store a value the console would never have written, and a value\n * that does not survive normalization names the field rather than storing\n * the raw string — a raw domain would never match the auto-association, and\n * a raw phone is the unusable half-number `normalizePhone` exists to end.\n */\nfunction readCompanyInput(\n body: Record<string, unknown>,\n { partial }: { partial: boolean },\n): { values: CompanyInput } | { errors: Record<string, string> } {\n const errors: Record<string, string> = {}\n const values: CompanyInput = {}\n const allowed = new Set(COMPANY_WRITABLE)\n if (!partial) allowed.add('consentSiteId')\n refuseUnknownKeys(body, allowed, 'company', errors)\n\n if (body.name !== undefined || !partial) {\n const name = String(body.name ?? '')\n .trim()\n .slice(0, CRM_TITLE_MAX)\n if (name) values.name = name\n else errors.name = partial ? 'Must not be empty' : 'A name is required'\n }\n\n\n if (body.mediaIds !== undefined) {\n if (!Array.isArray(body.mediaIds)) {\n errors.mediaIds = 'Must be an array of media ids'\n } else if (body.mediaIds.length > CRM_MEDIA_IDS_MAX) {\n errors.mediaIds = `At most ${CRM_MEDIA_IDS_MAX} files may be attached`\n } else {\n // The SAME normalizer the console card writes through, so the API\n // cannot store a list the console would refuse. An empty array is\n // legal and clears the attachments.\n values.mediaIds = normalizeCrmMediaIds(body.mediaIds)\n }\n }\n\n const domain = readOptionalText(body, 'domain', CRM_TITLE_MAX, errors)\n if (domain) {\n const normalized = normalizeCompanyDomain(domain)\n if (normalized) values.domain = normalized\n else errors.domain = 'Must be a domain name, like example.com'\n } else if (domain === null) {\n values.domain = null\n }\n\n const website = readOptionalText(body, 'website', CRM_TITLE_MAX * 4, errors)\n if (website) {\n // A bare `example.com` is what people paste; stored with the scheme so the\n // console can render it as a link without guessing one.\n const withScheme = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(website)\n ? website\n : `https://${website}`\n let parsed: URL | null\n try {\n parsed = new URL(withScheme)\n } catch {\n parsed = null\n }\n if (parsed && /^https?:$/.test(parsed.protocol) && normalizeCompanyDomain(parsed.hostname)) {\n values.website = parsed.toString()\n } else {\n errors.website = 'Must be a web address, like https://example.com'\n }\n } else if (website === null) {\n values.website = null\n }\n\n const phone = readOptionalText(body, 'phone', CRM_LABEL_MAX, errors)\n if (phone) {\n const normalized = normalizePhone(phone)\n if (normalized) values.phone = normalized\n else errors.phone = 'Must be a phone number with a country code, like +15125550123'\n } else if (phone === null) {\n values.phone = null\n }\n\n if (body.address !== undefined) {\n if (body.address === null) {\n values.address = null\n } else if (typeof body.address !== 'object' || Array.isArray(body.address)) {\n errors.address = 'Must be an address object'\n } else {\n // A blank address normalizes to `null`, which clears — an object of\n // empty strings must not read as \"has an address\".\n values.address = normalizeAddress(body.address as never)\n }\n }\n\n const industry = readOptionalText(body, 'industry', CRM_LABEL_MAX, errors)\n if (industry !== undefined) values.industry = industry\n\n const ownerUid = readOptionalText(body, 'ownerUid', CRM_LABEL_MAX, errors)\n if (ownerUid !== undefined) values.ownerUid = ownerUid\n\n const notes = readOptionalText(body, 'notes', CRM_TEXT_MAX, errors)\n if (notes !== undefined) values.notes = notes\n\n // `custom` is shape-checked here and judged against the org's\n // definitions by the writers, which is where the read is paid.\n if (body.custom !== undefined) {\n if (!body.custom || typeof body.custom !== 'object' || Array.isArray(body.custom)) {\n errors.custom = 'Must be an object of field values keyed by field key'\n }\n }\n\n return Object.keys(errors).length ? { errors } : { values }\n}\n\n/**\n * `POST /v1/companies`. Claimed first and released on the duplicate, the\n * ordering `createContact` argues for: a refusal that clears when the\n * duplicate is removed must not burn the key the retry will carry.\n */\nasync function createCompany(\n request: Request,\n ctx: ApiV1Context,\n): Promise<Response> {\n const body = await readJsonBody(request)\n const parsed = readCompanyInput(body, { partial: false })\n if ('errors' in parsed) return crmValidationFailed(ctx, 'company', parsed.errors)\n const site = readCrmSite(ctx, 'company', body)\n if ('response' in site) return site.response\n const owner = await memberError(ctx, 'ownerUid', parsed.values.ownerUid)\n if (Object.keys(owner).length) return crmValidationFailed(ctx, 'company', owner)\n // Judged against the org's company definitions, above the claim like\n // every other deterministic 400 (AGL-2661).\n const custom = await readCrmCustomBody(ctx, body, 'company')\n if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors)\n const customValues = custom && 'values' in custom ? custom.values : {}\n\n const collection = crmCollection(ctx, CRM_COLLECTIONS.companies)\n const claimed = await claimWrite(\n ctx,\n '*',\n request.headers.get('Idempotency-Key'),\n 'companies',\n )\n if ('replay' in claimed) return claimed.replay\n const { claim } = claimed\n\n try {\n const { name, domain, ...rest } = parsed.values\n if (domain) {\n const existing = await collection.where('domain', '==', domain).limit(1).get()\n if (!existing.empty) {\n await claim.release()\n return ApiErrors.conflict({\n message: `A company with this domain already exists (${existing.docs[0].id}). Update it instead.`,\n code: 'company_exists',\n headers: ctx.headers,\n })\n }\n }\n // The records band (AGL-2611), after the duplicate check for the reason\n // the claim ordering gives: a refusal that clears when the band is raised\n // must not burn the key the retry will carry.\n const bandFull = await crmRecordsBandRefusal(ctx)\n if (bandFull) {\n await claim.release()\n return bandFull\n }\n const id = createResourceUid()\n const record: Record<string, unknown> = {\n // `nameLower`/`nameTokens` travel with the name: the console's company\n // list searches the collection, not the page it fetched.\n ...nameSearchFields(name ?? ''),\n ...createPayload({ domain, ...rest }),\n // An empty map writes no `custom` key at all; a `null` inside one is\n // an explicit clear a fresh record has no use for.\n ...(Object.keys(customValues).length\n ? { custom: createPayload(customValues) }\n : {}),\n ...crmCreateStamp(ctx, site.siteId),\n }\n // What the console's Companies list searches and filters by (AGL-3321).\n await collection.doc(id).create({ ...record, ...crmNewRecordListFields('companies', record) })\n const view = companyView(await collection.doc(id).get())\n // Stored as 200 so a replay is distinguishable from the fresh 201.\n await claim.record(200, view)\n return apiJson(view, { status: 201, headers: ctx.headers })\n } catch (error) {\n await claim.release()\n throw error\n }\n}\n\n/** `PATCH /v1/companies/{id}` — no key, for `updateContact`'s reason. */\nasync function updateCompany(\n request: Request,\n ctx: ApiV1Context,\n ref: FirebaseFirestore.DocumentReference,\n): Promise<Response> {\n const body = await readJsonBody(request)\n const parsed = readCompanyInput(body, { partial: true })\n if ('errors' in parsed) return crmValidationFailed(ctx, 'company', parsed.errors)\n const snap = await ref.get()\n if (!snap.exists) {\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n const owner = await memberError(ctx, 'ownerUid', parsed.values.ownerUid)\n if (Object.keys(owner).length) return crmValidationFailed(ctx, 'company', owner)\n const custom = await readCrmCustomBody(ctx, body, 'company')\n if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors)\n\n const { name, domain, ...rest } = parsed.values\n if (domain && domain !== snap.get('domain')) {\n const existing = await ref.parent.where('domain', '==', domain).limit(1).get()\n if (!existing.empty && existing.docs[0].id !== ref.id) {\n return ApiErrors.conflict({\n message: `A company with this domain already exists (${existing.docs[0].id}).`,\n code: 'company_exists',\n headers: ctx.headers,\n })\n }\n }\n const update: Record<string, unknown> = {\n ...(name !== undefined ? nameSearchFields(name) : {}),\n ...updatePayload({ domain, ...rest }),\n ...(custom && 'values' in custom ? crmCustomUpdate(custom.values) : {}),\n }\n // An empty body is a no-op answered with the current company.\n if (Object.keys(update).length > 0) {\n await ref.update({ ...update, updatedAt: Timestamp.now() })\n // What the console's Companies list searches (AGL-3321).\n await restampCrmListFieldsAt(ref, 'companies')\n }\n return apiJson(companyView(await ref.get()), { headers: ctx.headers })\n}\n\n/**\n * `DELETE /v1/companies/{id}` — the company alone. The deals, tasks and\n * activities filed against it keep their `companyId`; they are records of\n * their own, and a delete that cascaded through them would erase a sales\n * history because somebody removed a duplicate account.\n */\nasync function deleteCompany(\n request: Request,\n ctx: ApiV1Context,\n ref: FirebaseFirestore.DocumentReference,\n): Promise<Response> {\n const claimed = await claimWrite(\n ctx,\n '*',\n request.headers.get('Idempotency-Key'),\n 'company-deletes',\n )\n if ('replay' in claimed) return claimed.replay\n const { claim } = claimed\n try {\n const snap = await ref.get()\n if (!snap.exists) {\n await claim.release()\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n await ref.delete()\n const view = { id: ref.id, object: 'company', deleted: true }\n await claim.record(200, view)\n return apiJson(view, { headers: ctx.headers })\n } catch (error) {\n await claim.release()\n throw error\n }\n}\n\n/**\n * `GET /v1/companies` filters. `domain` is normalized exactly as the write\n * stores it, so `?domain=https://www.Example.com/about` finds `example.com`; a\n * value that is not a domain at all is a `400`, not an empty page, for the\n * reason `listContacts` gives about `?email=`.\n */\nasync function listCompanies(\n ctx: ApiV1Context,\n collection: FirebaseFirestore.CollectionReference,\n url: URL,\n): Promise<Response> {\n const rawDomain = url.searchParams.get('domain')\n const filters = readEqualityFilters(url, ['ownerUid'])\n if (rawDomain !== null && rawDomain.trim() !== '') {\n const domain = normalizeCompanyDomain(rawDomain)\n if (!domain) {\n return crmValidationFailed(ctx, 'company filter', {\n domain: 'Must be a domain name, like example.com',\n })\n }\n // The domain is unique, so it is the clause that goes to Firestore.\n filters.unshift({ field: 'domain', value: domain })\n }\n return listCrm(ctx, collection, url, filters, companyView)\n}\n\nexport async function handleCompanies(\n request: Request,\n ctx: ApiV1Context,\n segments: string[],\n url: URL,\n): Promise<Response> {\n const collection = crmCollection(ctx, CRM_COLLECTIONS.companies)\n const [, companyId] = segments\n\n if (!companyId) {\n if (request.method === 'GET') {\n const denied = requireScope(ctx, 'crm:read')\n if (denied) return denied\n return listCompanies(ctx, collection, url)\n }\n if (request.method === 'POST') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return createCompany(request, ctx)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, POST' },\n })\n }\n\n const ref = collection.doc(companyId)\n if (request.method === 'GET') {\n const denied = requireScope(ctx, 'crm:read')\n if (denied) return denied\n const snap = await ref.get()\n if (!snap.exists) {\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n return apiJson(companyView(snap), { headers: ctx.headers })\n }\n if (request.method === 'PATCH') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return updateCompany(request, ctx, ref)\n }\n if (request.method === 'DELETE') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return deleteCompany(request, ctx, ref)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, PATCH, DELETE' },\n })\n}\n"],"names":["nameSearchFields","CRM_COLLECTIONS","CRM_MEDIA_IDS_MAX","createResourceUid","crmNewRecordListFields","normalizeAddress","normalizeCompanyDomain","normalizeCrmMediaIds","normalizePhone","apiJson","ApiErrors","restampCrmListFieldsAt","Timestamp","claimWrite","readJsonBody","requireScope","CRM_LABEL_MAX","CRM_TEXT_MAX","CRM_TITLE_MAX","createPayload","crmCollection","crmCreateStamp","crmCustomUpdate","crmCustomView","crmRecordsBandRefusal","crmTimes","crmValidationFailed","isoFromMs","listCrm","memberError","readCrmCustomBody","readCrmSite","readEqualityFilters","readOptionalText","refuseUnknownKeys","updatePayload","companyView","doc","data","id","object","name","domain","website","phone","address","industry","ownerUid","notes","custom","nextTaskAt","nextTaskAtMs","mediaIds","siteId","hostId","COMPANY_WRITABLE","Set","readCompanyInput","body","partial","errors","values","allowed","add","undefined","String","trim","slice","Array","isArray","length","normalized","withScheme","test","parsed","URL","protocol","hostname","toString","Object","keys","createCompany","request","ctx","site","response","owner","customValues","collection","companies","claimed","headers","get","replay","claim","rest","existing","where","limit","empty","release","conflict","message","docs","code","bandFull","record","create","view","status","error","updateCompany","ref","snap","exists","notFound","parent","update","updatedAt","now","deleteCompany","delete","deleted","listCompanies","url","rawDomain","searchParams","filters","unshift","field","value","handleCompanies","segments","companyId","method","denied","methodNotAllowed","Allow"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/server/api-v1/crm-companies.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * `/v1/companies` (AGL-2606) — the organizations behind the people.\n *\n * A company is keyed, in practice, by its domain: two contacts at\n * `example.com` work for one company, and the console's auto-association\n * (`companyDomainForEmail`) files them under it by that string. So the\n * domain is normalized exactly as the console stores it, a second company on\n * a domain already held is a `409 company_exists` naming the first — the\n * contact create's own rule for a second row on one email — and `?domain=`\n * is the lookup a sync starts with.\n *\n * Salesforce's Account fields (AGL-3514) ride the same object: Type,\n * Industry, Rating, Ownership and Account Source are labels of the org's\n * lists — any other value is a 400 naming what the list allows, and the\n * value a company already holds is kept — the rest are read through\n * `readCrmCompanyAccountFields`, and `parentCompanyId` names another\n * company of the organization that is not this one or below it.\n */\nimport { nameSearchFields } from '@aglyn/aglyn/app-utils/name-search'\nimport {\n CRM_COLLECTIONS,\n CRM_COMPANY_ACCOUNT_FIELDS,\n CRM_COMPANY_PICKLIST_FIELDS,\n CRM_MEDIA_IDS_MAX,\n type CrmCompanyAccountField,\n type CrmCompanyPicklistField,\n type CrmPicklist,\n type CrmPicklistId,\n createResourceUid,\n crmCompanyParentId,\n crmCompanyParentRefusal,\n crmNewRecordListFields,\n judgeCrmCompanyPicklists,\n normalizeAddress,\n normalizeCompanyDomain,\n normalizeCrmMediaIds,\n normalizePhone,\n readCrmCompanyAccountFields,\n} from '@aglyn/aglyn/server'\nimport { detachChildCompanies } from '../company-children'\nimport { readCrmPicklist } from '../read-picklist'\nimport { apiJson, ApiErrors, restampCrmListFieldsAt } from '@aglyn/tenant-data-admin'\nimport { Timestamp } from 'firebase-admin/firestore'\nimport {\n type ApiV1Context,\n claimWrite,\n readJsonBody,\n requireScope,\n} from '@aglyn/tenant-data-admin/server/api-v1-kit'\nimport {\n type Clearable,\n CRM_LABEL_MAX,\n CRM_TEXT_MAX,\n CRM_TITLE_MAX,\n createPayload,\n crmCollection,\n crmCreateStamp,\n crmCustomUpdate,\n crmCustomView,\n crmRecordsBandRefusal,\n crmTimes,\n crmValidationFailed,\n isoFromMs,\n listCrm,\n memberError,\n readCrmCustomBody,\n readCrmSite,\n readEqualityFilters,\n readOptionalText,\n refuseUnknownKeys,\n updatePayload,\n} from './crm-shared'\n\n/** The company object as published. Every writable field appears here. */\nfunction companyView(doc: FirebaseFirestore.DocumentSnapshot) {\n const data = doc.data() ?? {}\n return {\n id: doc.id,\n object: 'company',\n name: data.name ?? null,\n domain: data.domain ?? null,\n website: data.website ?? null,\n phone: data.phone ?? null,\n // The billing address, under the name it always had.\n address: data.address ?? null,\n industry: data.industry ?? null,\n // Salesforce's Account fields (AGL-3514).\n type: data.type ?? null,\n rating: data.rating ?? null,\n ownership: data.ownership ?? null,\n accountSource: data.accountSource ?? null,\n annualRevenueCents: typeof data.annualRevenueCents === 'number' ? data.annualRevenueCents : null,\n // `'usd'` when absent, as a deal's is.\n currency: data.currency ?? 'usd',\n numberOfEmployees: typeof data.numberOfEmployees === 'number' ? data.numberOfEmployees : null,\n fax: data.fax ?? null,\n accountNumber: data.accountNumber ?? null,\n site: data.site ?? null,\n tickerSymbol: data.tickerSymbol ?? null,\n sicCode: data.sicCode ?? null,\n shippingAddress: data.shippingAddress ?? null,\n parentCompanyId: crmCompanyParentId(data.parentCompanyId),\n ownerUid: data.ownerUid ?? null,\n notes: data.notes ?? null,\n // The org's company custom fields, keyed by field key (AGL-2661).\n custom: crmCustomView(data),\n // When the earliest open task against the company is due — see\n // `CrmDeal.nextTaskAtMs`. Read-only: the tasks resource maintains it.\n nextTaskAt: isoFromMs(data.nextTaskAtMs),\n mediaIds: normalizeCrmMediaIds(data.mediaIds),\n siteId: data.hostId ?? null,\n ...crmTimes(data),\n }\n}\n\nconst COMPANY_WRITABLE = new Set([\n 'name',\n 'domain',\n 'website',\n 'phone',\n 'address',\n 'industry',\n 'ownerUid',\n 'notes',\n 'custom',\n 'mediaIds',\n // Salesforce's Account fields (AGL-3514).\n ...CRM_COMPANY_PICKLIST_FIELDS.map((entry) => entry.field),\n ...CRM_COMPANY_ACCOUNT_FIELDS,\n 'parentCompanyId',\n])\n\ninterface CompanyInput {\n name?: string\n domain?: Clearable<string>\n website?: Clearable<string>\n phone?: Clearable<string>\n address?: Clearable<ReturnType<typeof normalizeAddress>>\n ownerUid?: Clearable<string>\n notes?: Clearable<string>\n /** Org-library files attached to the company (AGL-2662), by media id. */\n mediaIds?: string[]\n /** Salesforce's other account fields, normalized (AGL-3514). */\n account?: Partial<Record<CrmCompanyAccountField, unknown>>\n parentCompanyId?: Clearable<string>\n}\n\n/**\n * The picklist fields as sent (AGL-3514), apart from the values stored as\n * read: the writers judge them against the org's lists, which is where\n * that read is paid.\n */\ntype CompanyPicklistInput = Partial<Record<CrmCompanyPicklistField, string | null>>\n\n/**\n * The writable half of a company, validated. `partial` separates PATCH from\n * POST as every reader in this API does: a create needs a name, an update\n * may send one field alone. Unknown keys are named, never dropped.\n *\n * `domain` and `phone` go through the console's own normalizers so the API\n * cannot store a value the console would never have written, and a value\n * that does not survive normalization names the field rather than storing\n * the raw string — a raw domain would never match the auto-association, and\n * a raw phone is the unusable half-number `normalizePhone` exists to end.\n */\nfunction readCompanyInput(\n body: Record<string, unknown>,\n { partial }: { partial: boolean },\n): { values: CompanyInput; picklists: CompanyPicklistInput } | { errors: Record<string, string> } {\n const errors: Record<string, string> = {}\n const values: CompanyInput = {}\n const picklists: CompanyPicklistInput = {}\n const allowed = new Set(COMPANY_WRITABLE)\n if (!partial) allowed.add('consentSiteId')\n refuseUnknownKeys(body, allowed, 'company', errors)\n\n if (body.name !== undefined || !partial) {\n const name = String(body.name ?? '')\n .trim()\n .slice(0, CRM_TITLE_MAX)\n if (name) values.name = name\n else errors.name = partial ? 'Must not be empty' : 'A name is required'\n }\n\n\n if (body.mediaIds !== undefined) {\n if (!Array.isArray(body.mediaIds)) {\n errors.mediaIds = 'Must be an array of media ids'\n } else if (body.mediaIds.length > CRM_MEDIA_IDS_MAX) {\n errors.mediaIds = `At most ${CRM_MEDIA_IDS_MAX} files may be attached`\n } else {\n // The SAME normalizer the console card writes through, so the API\n // cannot store a list the console would refuse. An empty array is\n // legal and clears the attachments.\n values.mediaIds = normalizeCrmMediaIds(body.mediaIds)\n }\n }\n\n const domain = readOptionalText(body, 'domain', CRM_TITLE_MAX, errors)\n if (domain) {\n const normalized = normalizeCompanyDomain(domain)\n if (normalized) values.domain = normalized\n else errors.domain = 'Must be a domain name, like example.com'\n } else if (domain === null) {\n values.domain = null\n }\n\n const website = readOptionalText(body, 'website', CRM_TITLE_MAX * 4, errors)\n if (website) {\n // A bare `example.com` is what people paste; stored with the scheme so the\n // console can render it as a link without guessing one.\n const withScheme = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(website)\n ? website\n : `https://${website}`\n let parsed: URL | null\n try {\n parsed = new URL(withScheme)\n } catch {\n parsed = null\n }\n if (parsed && /^https?:$/.test(parsed.protocol) && normalizeCompanyDomain(parsed.hostname)) {\n values.website = parsed.toString()\n } else {\n errors.website = 'Must be a web address, like https://example.com'\n }\n } else if (website === null) {\n values.website = null\n }\n\n const phone = readOptionalText(body, 'phone', CRM_LABEL_MAX, errors)\n if (phone) {\n const normalized = normalizePhone(phone)\n if (normalized) values.phone = normalized\n else errors.phone = 'Must be a phone number with a country code, like +15125550123'\n } else if (phone === null) {\n values.phone = null\n }\n\n if (body.address !== undefined) {\n if (body.address === null) {\n values.address = null\n } else if (typeof body.address !== 'object' || Array.isArray(body.address)) {\n errors.address = 'Must be an address object'\n } else {\n // A blank address normalizes to `null`, which clears — an object of\n // empty strings must not read as \"has an address\".\n values.address = normalizeAddress(body.address as never)\n }\n }\n\n for (const { field } of CRM_COMPANY_PICKLIST_FIELDS) {\n const label = readOptionalText(body, field, CRM_LABEL_MAX, errors)\n if (label !== undefined) picklists[field] = label\n }\n const account = readCrmCompanyAccountFields(body)\n Object.assign(errors, account.errors)\n values.account = account.values\n\n const parentCompanyId = readOptionalText(body, 'parentCompanyId', CRM_LABEL_MAX, errors)\n if (parentCompanyId && parentCompanyId.includes('/')) errors.parentCompanyId = 'No such company'\n else if (parentCompanyId !== undefined) values.parentCompanyId = parentCompanyId\n\n const ownerUid = readOptionalText(body, 'ownerUid', CRM_LABEL_MAX, errors)\n if (ownerUid !== undefined) values.ownerUid = ownerUid\n\n const notes = readOptionalText(body, 'notes', CRM_TEXT_MAX, errors)\n if (notes !== undefined) values.notes = notes\n\n // `custom` is shape-checked here and judged against the org's\n // definitions by the writers, which is where the read is paid.\n if (body.custom !== undefined) {\n if (!body.custom || typeof body.custom !== 'object' || Array.isArray(body.custom)) {\n errors.custom = 'Must be an object of field values keyed by field key'\n }\n }\n\n return Object.keys(errors).length ? { errors } : { values, picklists }\n}\n\n/** The org's list behind every company picklist field the body names. */\nasync function readNamedPicklists(\n ctx: ApiV1Context,\n named: CompanyPicklistInput,\n created: boolean,\n): Promise<Partial<Record<CrmPicklistId, CrmPicklist>>> {\n // A create starts every field from its list's default, so it reads them all.\n const ids = [\n ...new Set(\n CRM_COMPANY_PICKLIST_FIELDS.filter((entry) => created || named[entry.field] !== undefined).map(\n (entry) => entry.picklistId,\n ),\n ),\n ]\n const lists = await Promise.all(ids.map((id) => readCrmPicklist(ctx.firestore, ctx.orgId, id)))\n return Object.fromEntries(ids.map((id, at) => [id, lists[at]]))\n}\n\n/**\n * The picklist values and the parent a write stores, or the 400's fields:\n * each label judged against its list with the company's `current` value\n * kept, and a parent that is this company, one below it, or none the\n * organization holds refused by name.\n */\nasync function judgeCompanyReferences(\n ctx: ApiV1Context,\n collection: FirebaseFirestore.CollectionReference,\n input: { picklists: CompanyPicklistInput; parentCompanyId?: Clearable<string> },\n options: { companyId: string | null; current: Record<string, unknown> },\n): Promise<\n | { picklists: Partial<Record<CrmCompanyPicklistField, string | null>> }\n | { errors: Record<string, string> }\n> {\n const created = options.companyId === null\n const lists = await readNamedPicklists(ctx, input.picklists, created)\n const judged = judgeCrmCompanyPicklists(lists, input.picklists, {\n current: options.current,\n created,\n })\n const errors = { ...judged.errors }\n const parentId = input.parentCompanyId\n if (parentId && parentId !== crmCompanyParentId(options.current['parentCompanyId'])) {\n const refusal = await crmCompanyParentRefusal(options.companyId, parentId, async (id) => {\n const snapshot = await collection.doc(id).get()\n return snapshot.exists ? { parentCompanyId: crmCompanyParentId(snapshot.get('parentCompanyId')) } : null\n })\n if (refusal) errors.parentCompanyId = refusal\n }\n return Object.keys(errors).length ? { errors } : { picklists: judged.values }\n}\n\n/**\n * `POST /v1/companies`. Claimed first and released on the duplicate, the\n * ordering `createContact` argues for: a refusal that clears when the\n * duplicate is removed must not burn the key the retry will carry.\n */\nasync function createCompany(\n request: Request,\n ctx: ApiV1Context,\n): Promise<Response> {\n const body = await readJsonBody(request)\n const parsed = readCompanyInput(body, { partial: false })\n if ('errors' in parsed) return crmValidationFailed(ctx, 'company', parsed.errors)\n const site = readCrmSite(ctx, 'company', body)\n if ('response' in site) return site.response\n const owner = await memberError(ctx, 'ownerUid', parsed.values.ownerUid)\n if (Object.keys(owner).length) return crmValidationFailed(ctx, 'company', owner)\n // Judged against the org's company definitions, above the claim like\n // every other deterministic 400 (AGL-2661).\n const custom = await readCrmCustomBody(ctx, body, 'company')\n if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors)\n const customValues = custom && 'values' in custom ? custom.values : {}\n\n const collection = crmCollection(ctx, CRM_COLLECTIONS.companies)\n // The org's lists and the parent (AGL-3514), above the claim with the\n // other deterministic 400s.\n const references = await judgeCompanyReferences(\n ctx,\n collection,\n { picklists: parsed.picklists, parentCompanyId: parsed.values.parentCompanyId },\n { companyId: null, current: {} },\n )\n if ('errors' in references) return crmValidationFailed(ctx, 'company', references.errors)\n const claimed = await claimWrite(\n ctx,\n '*',\n request.headers.get('Idempotency-Key'),\n 'companies',\n )\n if ('replay' in claimed) return claimed.replay\n const { claim } = claimed\n\n try {\n const { name, domain, account, ...rest } = parsed.values\n if (domain) {\n const existing = await collection.where('domain', '==', domain).limit(1).get()\n if (!existing.empty) {\n await claim.release()\n return ApiErrors.conflict({\n message: `A company with this domain already exists (${existing.docs[0].id}). Update it instead.`,\n code: 'company_exists',\n headers: ctx.headers,\n })\n }\n }\n // The records band (AGL-2611), after the duplicate check for the reason\n // the claim ordering gives: a refusal that clears when the band is raised\n // must not burn the key the retry will carry.\n const bandFull = await crmRecordsBandRefusal(ctx)\n if (bandFull) {\n await claim.release()\n return bandFull\n }\n const id = createResourceUid()\n const record: Record<string, unknown> = {\n // `nameLower`/`nameTokens` travel with the name: the console's company\n // list searches the collection, not the page it fetched.\n ...nameSearchFields(name ?? ''),\n ...createPayload({ domain, ...rest, ...references.picklists, ...account }),\n // An empty map writes no `custom` key at all; a `null` inside one is\n // an explicit clear a fresh record has no use for.\n ...(Object.keys(customValues).length\n ? { custom: createPayload(customValues) }\n : {}),\n ...crmCreateStamp(ctx, site.siteId),\n }\n // What the console's Companies list searches and filters by (AGL-3321).\n await collection.doc(id).create({ ...record, ...crmNewRecordListFields('companies', record) })\n const view = companyView(await collection.doc(id).get())\n // Stored as 200 so a replay is distinguishable from the fresh 201.\n await claim.record(200, view)\n return apiJson(view, { status: 201, headers: ctx.headers })\n } catch (error) {\n await claim.release()\n throw error\n }\n}\n\n/** `PATCH /v1/companies/{id}` — no key, for `updateContact`'s reason. */\nasync function updateCompany(\n request: Request,\n ctx: ApiV1Context,\n ref: FirebaseFirestore.DocumentReference,\n): Promise<Response> {\n const body = await readJsonBody(request)\n const parsed = readCompanyInput(body, { partial: true })\n if ('errors' in parsed) return crmValidationFailed(ctx, 'company', parsed.errors)\n const snap = await ref.get()\n if (!snap.exists) {\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n const owner = await memberError(ctx, 'ownerUid', parsed.values.ownerUid)\n if (Object.keys(owner).length) return crmValidationFailed(ctx, 'company', owner)\n const custom = await readCrmCustomBody(ctx, body, 'company')\n if (custom && 'errors' in custom) return crmValidationFailed(ctx, 'company', custom.errors)\n const references = await judgeCompanyReferences(\n ctx,\n ref.parent,\n { picklists: parsed.picklists, parentCompanyId: parsed.values.parentCompanyId },\n { companyId: ref.id, current: snap.data() ?? {} },\n )\n if ('errors' in references) return crmValidationFailed(ctx, 'company', references.errors)\n\n const { name, domain, account, ...rest } = parsed.values\n if (domain && domain !== snap.get('domain')) {\n const existing = await ref.parent.where('domain', '==', domain).limit(1).get()\n if (!existing.empty && existing.docs[0].id !== ref.id) {\n return ApiErrors.conflict({\n message: `A company with this domain already exists (${existing.docs[0].id}).`,\n code: 'company_exists',\n headers: ctx.headers,\n })\n }\n }\n const update: Record<string, unknown> = {\n ...(name !== undefined ? nameSearchFields(name) : {}),\n ...updatePayload({ domain, ...rest, ...references.picklists, ...account }),\n ...(custom && 'values' in custom ? crmCustomUpdate(custom.values) : {}),\n }\n // An empty body is a no-op answered with the current company.\n if (Object.keys(update).length > 0) {\n await ref.update({ ...update, updatedAt: Timestamp.now() })\n // What the console's Companies list searches (AGL-3321) and filters\n // by (AGL-3514).\n await restampCrmListFieldsAt(ref, 'companies')\n }\n return apiJson(companyView(await ref.get()), { headers: ctx.headers })\n}\n\n/**\n * `DELETE /v1/companies/{id}` — the company alone. The deals, tasks and\n * activities filed against it keep their `companyId`; they are records of\n * their own, and a delete that cascaded through them would erase a sales\n * history because somebody removed a duplicate account. The companies\n * under it keep everything but their `parentCompanyId` (AGL-3514).\n */\nasync function deleteCompany(\n request: Request,\n ctx: ApiV1Context,\n ref: FirebaseFirestore.DocumentReference,\n): Promise<Response> {\n const claimed = await claimWrite(\n ctx,\n '*',\n request.headers.get('Idempotency-Key'),\n 'company-deletes',\n )\n if ('replay' in claimed) return claimed.replay\n const { claim } = claimed\n try {\n const snap = await ref.get()\n if (!snap.exists) {\n await claim.release()\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n // The companies under it stand on their own (AGL-3514): their parent is\n // cleared, a batch at a time, before it goes.\n for (;;) {\n const pass = await detachChildCompanies(ctx.firestore, ref.parent, ref.id)\n if (!pass.moreRemain) break\n }\n await ref.delete()\n const view = { id: ref.id, object: 'company', deleted: true }\n await claim.record(200, view)\n return apiJson(view, { headers: ctx.headers })\n } catch (error) {\n await claim.release()\n throw error\n }\n}\n\n/**\n * `GET /v1/companies` filters. `domain` is normalized exactly as the write\n * stores it, so `?domain=https://www.Example.com/about` finds `example.com`; a\n * value that is not a domain at all is a `400`, not an empty page, for the\n * reason `listContacts` gives about `?email=`.\n */\nasync function listCompanies(\n ctx: ApiV1Context,\n collection: FirebaseFirestore.CollectionReference,\n url: URL,\n): Promise<Response> {\n const rawDomain = url.searchParams.get('domain')\n const filters = readEqualityFilters(url, ['ownerUid'])\n if (rawDomain !== null && rawDomain.trim() !== '') {\n const domain = normalizeCompanyDomain(rawDomain)\n if (!domain) {\n return crmValidationFailed(ctx, 'company filter', {\n domain: 'Must be a domain name, like example.com',\n })\n }\n // The domain is unique, so it is the clause that goes to Firestore.\n filters.unshift({ field: 'domain', value: domain })\n }\n return listCrm(ctx, collection, url, filters, companyView)\n}\n\nexport async function handleCompanies(\n request: Request,\n ctx: ApiV1Context,\n segments: string[],\n url: URL,\n): Promise<Response> {\n const collection = crmCollection(ctx, CRM_COLLECTIONS.companies)\n const [, companyId] = segments\n\n if (!companyId) {\n if (request.method === 'GET') {\n const denied = requireScope(ctx, 'crm:read')\n if (denied) return denied\n return listCompanies(ctx, collection, url)\n }\n if (request.method === 'POST') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return createCompany(request, ctx)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, POST' },\n })\n }\n\n const ref = collection.doc(companyId)\n if (request.method === 'GET') {\n const denied = requireScope(ctx, 'crm:read')\n if (denied) return denied\n const snap = await ref.get()\n if (!snap.exists) {\n return ApiErrors.notFound({ message: 'No such company', headers: ctx.headers })\n }\n return apiJson(companyView(snap), { headers: ctx.headers })\n }\n if (request.method === 'PATCH') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return updateCompany(request, ctx, ref)\n }\n if (request.method === 'DELETE') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return deleteCompany(request, ctx, ref)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, PATCH, DELETE' },\n })\n}\n"],"names":["nameSearchFields","CRM_COLLECTIONS","CRM_COMPANY_ACCOUNT_FIELDS","CRM_COMPANY_PICKLIST_FIELDS","CRM_MEDIA_IDS_MAX","createResourceUid","crmCompanyParentId","crmCompanyParentRefusal","crmNewRecordListFields","judgeCrmCompanyPicklists","normalizeAddress","normalizeCompanyDomain","normalizeCrmMediaIds","normalizePhone","readCrmCompanyAccountFields","detachChildCompanies","readCrmPicklist","apiJson","ApiErrors","restampCrmListFieldsAt","Timestamp","claimWrite","readJsonBody","requireScope","CRM_LABEL_MAX","CRM_TEXT_MAX","CRM_TITLE_MAX","createPayload","crmCollection","crmCreateStamp","crmCustomUpdate","crmCustomView","crmRecordsBandRefusal","crmTimes","crmValidationFailed","isoFromMs","listCrm","memberError","readCrmCustomBody","readCrmSite","readEqualityFilters","readOptionalText","refuseUnknownKeys","updatePayload","companyView","doc","data","id","object","name","domain","website","phone","address","industry","type","rating","ownership","accountSource","annualRevenueCents","currency","numberOfEmployees","fax","accountNumber","site","tickerSymbol","sicCode","shippingAddress","parentCompanyId","ownerUid","notes","custom","nextTaskAt","nextTaskAtMs","mediaIds","siteId","hostId","COMPANY_WRITABLE","Set","map","entry","field","readCompanyInput","body","partial","errors","values","picklists","allowed","add","undefined","String","trim","slice","Array","isArray","length","normalized","withScheme","test","parsed","URL","protocol","hostname","toString","label","account","Object","assign","includes","keys","readNamedPicklists","ctx","named","created","ids","filter","picklistId","lists","Promise","all","firestore","orgId","fromEntries","at","judgeCompanyReferences","collection","input","options","companyId","judged","current","parentId","refusal","snapshot","get","exists","createCompany","request","response","owner","customValues","companies","references","claimed","headers","replay","claim","rest","existing","where","limit","empty","release","conflict","message","docs","code","bandFull","record","create","view","status","error","updateCompany","ref","snap","notFound","parent","update","updatedAt","now","deleteCompany","pass","moreRemain","delete","deleted","listCompanies","url","rawDomain","searchParams","filters","unshift","value","handleCompanies","segments","method","denied","methodNotAllowed","Allow"],"mappings":"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"}
|