@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
|
@@ -30,37 +30,40 @@ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_wi
|
|
|
30
30
|
* it behind, and cleared by completion while it is still owed — the rule
|
|
31
31
|
* in `crmTaskReminderAfterEdit`, the same one the console's drawer keeps.
|
|
32
32
|
* `reminderSentAt` is read-only: when the hourly runner handled it.
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
*
|
|
34
|
+
* `kind`, `priority` and `status` (AGL-3517) take a value of the org's
|
|
35
|
+
* Type, Priority or Status picklist — its label, "In Progress" — or the
|
|
36
|
+
* meaning behind it, `open`; the task stores both, and answers the meaning
|
|
37
|
+
* under the field's own name with the label beside it as `typeLabel`,
|
|
38
|
+
* `priorityLabel` and `statusLabel`.
|
|
39
|
+
*/ import { CRM_COLLECTIONS, CRM_TASK_PICKLIST_IDS, crmPicklistLabelForNew, crmTaskPicklistLabels, createResourceUid, crmTaskListFields, resolveCrmSemanticPicklistWrite } from "@aglyn/aglyn/server";
|
|
40
|
+
import { apiJson, ApiErrors, restampCrmListFieldsAt } from "@aglyn/tenant-data-admin";
|
|
35
41
|
import { FieldValue, Timestamp } from "firebase-admin/firestore";
|
|
36
42
|
import { claimWrite, readJsonBody, requireScope } from "@aglyn/tenant-data-admin/server/api-v1-kit";
|
|
37
|
-
import { CRM_TEXT_MAX, CRM_TITLE_MAX, createPayload, crmCollection, crmCreateStamp, crmRefErrors, crmTimes, crmValidationFailed, isoFromMs, listCrm, memberError, parseIsoInstant,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
'meeting',
|
|
42
|
-
'todo'
|
|
43
|
-
];
|
|
44
|
-
const TASK_PRIORITIES = [
|
|
45
|
-
'low',
|
|
46
|
-
'normal',
|
|
47
|
-
'high'
|
|
48
|
-
];
|
|
43
|
+
import { CRM_TEXT_MAX, CRM_TITLE_MAX, createPayload, crmCollection, crmCreateStamp, crmRefErrors, crmTimes, crmValidationFailed, isoFromMs, listCrm, memberError, parseIsoInstant, readCrmSite, readEqualityFilters, readOptionalText, readRefId, refuseUnknownKeys, updatePayload } from "./crm-shared.js";
|
|
44
|
+
import { readCrmTaskPicklists } from "../read-picklist.js";
|
|
45
|
+
import { crmTaskReminderAfterEdit, crmTaskReminderPending } from "../../model/crm-task-reminders.js";
|
|
46
|
+
import { crmNextActivityLinksOf, recomputeCrmNextTaskAt } from "../crm-next-activity.js";
|
|
49
47
|
const TASK_STATUSES = [
|
|
50
48
|
'open',
|
|
51
49
|
'done'
|
|
52
50
|
];
|
|
53
|
-
/** The task
|
|
51
|
+
/** The org's task picklists, read once for a request. */ const taskPicklistsOf = (ctx)=>readCrmTaskPicklists(ctx.firestore, ctx.orgId);
|
|
52
|
+
/** The task object as published. Every writable field appears here. */ function taskView(doc, picklists) {
|
|
54
53
|
var _doc_data, _data_title, _data_notes, _data_kind, _data_priority, _data_status, _data_assigneeUid, _data_contactId, _data_companyId, _data_dealId, _data_hostId;
|
|
55
54
|
const data = (_doc_data = doc.data()) != null ? _doc_data : {};
|
|
55
|
+
const labels = crmTaskPicklistLabels(data, picklists);
|
|
56
56
|
return _extends({
|
|
57
57
|
id: doc.id,
|
|
58
58
|
object: 'task',
|
|
59
59
|
title: (_data_title = data.title) != null ? _data_title : null,
|
|
60
60
|
notes: (_data_notes = data.notes) != null ? _data_notes : null,
|
|
61
61
|
kind: (_data_kind = data.kind) != null ? _data_kind : 'todo',
|
|
62
|
+
typeLabel: labels.type,
|
|
62
63
|
priority: (_data_priority = data.priority) != null ? _data_priority : 'normal',
|
|
64
|
+
priorityLabel: labels.priority,
|
|
63
65
|
status: (_data_status = data.status) != null ? _data_status : 'open',
|
|
66
|
+
statusLabel: labels.status,
|
|
64
67
|
dueAt: isoFromMs(data.dueAtMs),
|
|
65
68
|
remindAt: isoFromMs(data.remindAtMs),
|
|
66
69
|
reminderSentAt: isoFromMs(data.reminderSentAtMs),
|
|
@@ -85,7 +88,24 @@ const TASK_WRITABLE = new Set([
|
|
|
85
88
|
'companyId',
|
|
86
89
|
'dealId'
|
|
87
90
|
]);
|
|
88
|
-
|
|
91
|
+
/**
|
|
92
|
+
* A Type, Priority or Status as the body names it — a label or a meaning —
|
|
93
|
+
* against the org's list; the stored label is kept when the body names it
|
|
94
|
+
* again. Absent answers `undefined`; anything the list does not hold is an
|
|
95
|
+
* error naming the values it does.
|
|
96
|
+
*/ function readPicklistField(body, key, id, picklists, stored, errors) {
|
|
97
|
+
const value = body[key];
|
|
98
|
+
if (value === undefined) return undefined;
|
|
99
|
+
const list = key === 'kind' ? picklists.type : key === 'priority' ? picklists.priority : picklists.status;
|
|
100
|
+
const resolved = typeof value === 'string' ? resolveCrmSemanticPicklistWrite(id, list, value, stored) : null;
|
|
101
|
+
if (resolved == null ? void 0 : resolved.ok) return {
|
|
102
|
+
meaning: resolved.meaning,
|
|
103
|
+
label: resolved.label
|
|
104
|
+
};
|
|
105
|
+
errors[key] = (resolved == null ? void 0 : resolved.ok) === false ? resolved.error : 'Must be a value of the list, or its meaning';
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
function readTaskInput(body, { partial }, picklists, stored = null) {
|
|
89
109
|
const errors = {};
|
|
90
110
|
const values = {};
|
|
91
111
|
const allowed = new Set(TASK_WRITABLE);
|
|
@@ -99,11 +119,11 @@ function readTaskInput(body, { partial }) {
|
|
|
99
119
|
}
|
|
100
120
|
const notes = readOptionalText(body, 'notes', CRM_TEXT_MAX, errors);
|
|
101
121
|
if (notes !== undefined) values.notes = notes;
|
|
102
|
-
const kind =
|
|
122
|
+
const kind = readPicklistField(body, 'kind', CRM_TASK_PICKLIST_IDS.type, picklists, stored == null ? void 0 : stored.typeLabel, errors);
|
|
103
123
|
if (kind) values.kind = kind;
|
|
104
|
-
const priority =
|
|
124
|
+
const priority = readPicklistField(body, 'priority', CRM_TASK_PICKLIST_IDS.priority, picklists, stored == null ? void 0 : stored.priorityLabel, errors);
|
|
105
125
|
if (priority) values.priority = priority;
|
|
106
|
-
const status =
|
|
126
|
+
const status = readPicklistField(body, 'status', CRM_TASK_PICKLIST_IDS.status, picklists, stored == null ? void 0 : stored.statusLabel, errors);
|
|
107
127
|
if (status) values.status = status;
|
|
108
128
|
if (body.dueAt !== undefined) {
|
|
109
129
|
if (body.dueAt === null) {
|
|
@@ -171,9 +191,10 @@ async function taskRefErrors(ctx, values) {
|
|
|
171
191
|
}
|
|
172
192
|
/** `POST /v1/tasks`. */ async function createTask(request, ctx) {
|
|
173
193
|
const body = await readJsonBody(request);
|
|
194
|
+
const picklists = await taskPicklistsOf(ctx);
|
|
174
195
|
const parsed = readTaskInput(body, {
|
|
175
196
|
partial: false
|
|
176
|
-
});
|
|
197
|
+
}, picklists);
|
|
177
198
|
if ('errors' in parsed) return crmValidationFailed(ctx, 'task', parsed.errors);
|
|
178
199
|
const site = readCrmSite(ctx, 'task', body);
|
|
179
200
|
if ('response' in site) return site.response;
|
|
@@ -184,21 +205,28 @@ async function taskRefErrors(ctx, values) {
|
|
|
184
205
|
if ('replay' in claimed) return claimed.replay;
|
|
185
206
|
const { claim } = claimed;
|
|
186
207
|
try {
|
|
187
|
-
var _rest_dueAtMs, _rest_dueAtMs1;
|
|
188
|
-
const _parsed_values = parsed.values, { title, kind, priority, status, remindAtMs } = _parsed_values, rest = _object_without_properties_loose(_parsed_values, [
|
|
208
|
+
var _ref, _ref1, _ref2, _rest_dueAtMs, _rest_dueAtMs1;
|
|
209
|
+
const _parsed_values = parsed.values, { title, kind: pickedKind, priority: pickedPriority, status: pickedStatus, remindAtMs } = _parsed_values, rest = _object_without_properties_loose(_parsed_values, [
|
|
189
210
|
"title",
|
|
190
211
|
"kind",
|
|
191
212
|
"priority",
|
|
192
213
|
"status",
|
|
193
214
|
"remindAtMs"
|
|
194
215
|
]);
|
|
216
|
+
const kind = (_ref = pickedKind == null ? void 0 : pickedKind.meaning) != null ? _ref : 'todo';
|
|
217
|
+
const priority = (_ref1 = pickedPriority == null ? void 0 : pickedPriority.meaning) != null ? _ref1 : 'normal';
|
|
218
|
+
const status = (_ref2 = pickedStatus == null ? void 0 : pickedStatus.meaning) != null ? _ref2 : 'open';
|
|
195
219
|
const id = createResourceUid();
|
|
196
220
|
const stamp = crmCreateStamp(ctx, site.siteId);
|
|
197
221
|
const record = _extends({
|
|
198
222
|
title,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
223
|
+
// Each meaning with the org's label beside it (AGL-3517).
|
|
224
|
+
kind,
|
|
225
|
+
typeLabel: pickedKind ? pickedKind.label : crmPicklistLabelForNew(picklists.type, kind),
|
|
226
|
+
priority,
|
|
227
|
+
priorityLabel: pickedPriority ? pickedPriority.label : crmPicklistLabelForNew(picklists.priority, priority),
|
|
228
|
+
status,
|
|
229
|
+
statusLabel: pickedStatus ? pickedStatus.label : crmPicklistLabelForNew(picklists.status, status)
|
|
202
230
|
}, status === 'done' ? {
|
|
203
231
|
completedAtMs: stamp.createdAt.toMillis()
|
|
204
232
|
} : {}, createPayload(_extends({}, rest, {
|
|
@@ -220,7 +248,7 @@ async function taskRefErrors(ctx, values) {
|
|
|
220
248
|
await settleNextActivity(ctx, [
|
|
221
249
|
rest
|
|
222
250
|
]);
|
|
223
|
-
const view = taskView(await collection.doc(id).get());
|
|
251
|
+
const view = taskView(await collection.doc(id).get(), picklists);
|
|
224
252
|
await claim.record(200, view);
|
|
225
253
|
return apiJson(view, {
|
|
226
254
|
status: 201,
|
|
@@ -232,10 +260,7 @@ async function taskRefErrors(ctx, values) {
|
|
|
232
260
|
}
|
|
233
261
|
}
|
|
234
262
|
/** `PATCH /v1/tasks/{id}`. */ async function updateTask(request, ctx, ref) {
|
|
235
|
-
const
|
|
236
|
-
partial: true
|
|
237
|
-
});
|
|
238
|
-
if ('errors' in parsed) return crmValidationFailed(ctx, 'task', parsed.errors);
|
|
263
|
+
const body = await readJsonBody(request);
|
|
239
264
|
const snap = await ref.get();
|
|
240
265
|
if (!snap.exists) {
|
|
241
266
|
return ApiErrors.notFound({
|
|
@@ -243,18 +268,36 @@ async function taskRefErrors(ctx, values) {
|
|
|
243
268
|
headers: ctx.headers
|
|
244
269
|
});
|
|
245
270
|
}
|
|
271
|
+
const picklists = await taskPicklistsOf(ctx);
|
|
272
|
+
const parsed = readTaskInput(body, {
|
|
273
|
+
partial: true
|
|
274
|
+
}, picklists, snap.data());
|
|
275
|
+
if ('errors' in parsed) return crmValidationFailed(ctx, 'task', parsed.errors);
|
|
246
276
|
const refErrors = await taskRefErrors(ctx, parsed.values);
|
|
247
277
|
if (Object.keys(refErrors).length) return crmValidationFailed(ctx, 'task', refErrors);
|
|
248
|
-
const _parsed_values = parsed.values, { status, remindAtMs } = _parsed_values, rest = _object_without_properties_loose(_parsed_values, [
|
|
278
|
+
const _parsed_values = parsed.values, { status: pickedStatus, kind: pickedKind, priority: pickedPriority, remindAtMs } = _parsed_values, rest = _object_without_properties_loose(_parsed_values, [
|
|
249
279
|
"status",
|
|
280
|
+
"kind",
|
|
281
|
+
"priority",
|
|
250
282
|
"remindAtMs"
|
|
251
283
|
]);
|
|
252
284
|
const update = updatePayload(rest);
|
|
285
|
+
// Each meaning with the org's label beside it (AGL-3517).
|
|
286
|
+
if (pickedKind) {
|
|
287
|
+
update.kind = pickedKind.meaning;
|
|
288
|
+
update.typeLabel = pickedKind.label;
|
|
289
|
+
}
|
|
290
|
+
if (pickedPriority) {
|
|
291
|
+
update.priority = pickedPriority.meaning;
|
|
292
|
+
update.priorityLabel = pickedPriority.label;
|
|
293
|
+
}
|
|
253
294
|
// A cleared due date is stored `null`, not deleted — see the create.
|
|
254
295
|
if (rest.dueAtMs === null) update.dueAtMs = null;
|
|
255
296
|
// One instant for the write: a task completed at T reads updated at T.
|
|
256
297
|
const now = Timestamp.now();
|
|
298
|
+
const status = pickedStatus == null ? void 0 : pickedStatus.meaning;
|
|
257
299
|
const completing = status === 'done' && status !== snap.get('status');
|
|
300
|
+
if (pickedStatus) update.statusLabel = pickedStatus.label;
|
|
258
301
|
if (status !== undefined && status !== snap.get('status')) {
|
|
259
302
|
update.status = status;
|
|
260
303
|
update.completedAtMs = status === 'done' ? now.toMillis() : null;
|
|
@@ -290,7 +333,7 @@ async function taskRefErrors(ctx, values) {
|
|
|
290
333
|
// What the console's Tasks list searches (AGL-3321).
|
|
291
334
|
if ('title' in update) await restampCrmListFieldsAt(ref, 'crmTasks');
|
|
292
335
|
}
|
|
293
|
-
return apiJson(taskView(await ref.get()), {
|
|
336
|
+
return apiJson(taskView(await ref.get(), picklists), {
|
|
294
337
|
headers: ctx.headers
|
|
295
338
|
});
|
|
296
339
|
}
|
|
@@ -341,7 +384,8 @@ async function taskRefErrors(ctx, values) {
|
|
|
341
384
|
'assigneeUid',
|
|
342
385
|
'status'
|
|
343
386
|
]);
|
|
344
|
-
|
|
387
|
+
const picklists = await taskPicklistsOf(ctx);
|
|
388
|
+
return listCrm(ctx, collection, url, filters, (doc)=>taskView(doc, picklists));
|
|
345
389
|
}
|
|
346
390
|
export async function handleTasks(request, ctx, segments, url) {
|
|
347
391
|
const collection = crmCollection(ctx, CRM_COLLECTIONS.tasks);
|
|
@@ -374,7 +418,7 @@ export async function handleTasks(request, ctx, segments, url) {
|
|
|
374
418
|
headers: ctx.headers
|
|
375
419
|
});
|
|
376
420
|
}
|
|
377
|
-
return apiJson(taskView(snap), {
|
|
421
|
+
return apiJson(taskView(snap, await taskPicklistsOf(ctx)), {
|
|
378
422
|
headers: ctx.headers
|
|
379
423
|
});
|
|
380
424
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/server/api-v1/crm-tasks.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/tasks` (AGL-2606) — what the team owes a person: a call, an email, a\n * meeting or a to-do, with a due date, pointing at the contact, company or\n * deal it is for. A task may point at nothing — a plain to-do is still a\n * task — which is the one place it differs from an activity.\n *\n * `status` is the only state machine here and it has two states. Marking a\n * task `done` stamps `completedAtMs`; marking it `open` again clears it, so\n * a reopened task never reads as completed on the date it was first closed.\n *\n * `remindAt` (AGL-2659) is the task's reminder: the due time unless the\n * body names a time or `null`, carried along when a moved due date leaves\n * it behind, and cleared by completion while it is still owed — the rule\n * in `crmTaskReminderAfterEdit`, the same one the console's drawer keeps.\n * `reminderSentAt` is read-only: when the hourly runner handled it.\n */\nimport {\n CRM_COLLECTIONS,\n type CrmTask,\n type CrmTaskKind,\n type CrmTaskPriority,\n crmTaskReminderAfterEdit,\n crmTaskReminderPending,\n type CrmTaskStatus,\n createResourceUid,\n crmTaskListFields,\n} from '@aglyn/aglyn/server'\nimport {\n apiJson,\n ApiErrors,\n crmNextActivityLinksOf,\n recomputeCrmNextTaskAt,\n restampCrmListFieldsAt,\n} from '@aglyn/tenant-data-admin'\nimport { FieldValue, 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_TEXT_MAX,\n CRM_TITLE_MAX,\n createPayload,\n crmCollection,\n crmCreateStamp,\n crmRefErrors,\n crmTimes,\n crmValidationFailed,\n isoFromMs,\n listCrm,\n memberError,\n parseIsoInstant,\n readChoice,\n readCrmSite,\n readEqualityFilters,\n readOptionalText,\n readRefId,\n refuseUnknownKeys,\n updatePayload,\n} from './crm-shared'\n\nconst TASK_KINDS = ['call', 'email', 'meeting', 'todo'] as const\nconst TASK_PRIORITIES = ['low', 'normal', 'high'] as const\nconst TASK_STATUSES = ['open', 'done'] as const\n\n/** The task object as published. Every writable field appears here. */\nfunction taskView(doc: FirebaseFirestore.DocumentSnapshot) {\n const data = (doc.data() ?? {}) as Partial<CrmTask>\n return {\n id: doc.id,\n object: 'task',\n title: data.title ?? null,\n notes: data.notes ?? null,\n kind: data.kind ?? 'todo',\n priority: data.priority ?? 'normal',\n status: data.status ?? 'open',\n dueAt: isoFromMs(data.dueAtMs),\n remindAt: isoFromMs(data.remindAtMs),\n reminderSentAt: isoFromMs(data.reminderSentAtMs),\n completedAt: isoFromMs(data.completedAtMs),\n assigneeUid: data.assigneeUid ?? null,\n contactId: data.contactId ?? null,\n companyId: data.companyId ?? null,\n dealId: data.dealId ?? null,\n siteId: data.hostId ?? null,\n ...crmTimes(data as FirebaseFirestore.DocumentData),\n }\n}\n\nconst TASK_WRITABLE = new Set([\n 'title',\n 'notes',\n 'kind',\n 'priority',\n 'status',\n 'dueAt',\n 'remindAt',\n 'assigneeUid',\n 'contactId',\n 'companyId',\n 'dealId',\n])\n\ninterface TaskInput {\n title?: string\n notes?: Clearable<string>\n kind?: CrmTaskKind\n priority?: CrmTaskPriority\n status?: CrmTaskStatus\n dueAtMs?: Clearable<number>\n remindAtMs?: Clearable<number>\n assigneeUid?: Clearable<string>\n contactId?: Clearable<string>\n companyId?: Clearable<string>\n dealId?: Clearable<string>\n}\n\nfunction readTaskInput(\n body: Record<string, unknown>,\n { partial }: { partial: boolean },\n): { values: TaskInput } | { errors: Record<string, string> } {\n const errors: Record<string, string> = {}\n const values: TaskInput = {}\n const allowed = new Set(TASK_WRITABLE)\n if (!partial) allowed.add('consentSiteId')\n refuseUnknownKeys(body, allowed, 'task', errors)\n\n if (body.title !== undefined || !partial) {\n const title = String(body.title ?? '')\n .trim()\n .slice(0, CRM_TITLE_MAX)\n if (title) values.title = title\n else errors.title = partial ? 'Must not be empty' : 'A title is required'\n }\n\n const notes = readOptionalText(body, 'notes', CRM_TEXT_MAX, errors)\n if (notes !== undefined) values.notes = notes\n const kind = readChoice(body, 'kind', TASK_KINDS, errors)\n if (kind) values.kind = kind\n const priority = readChoice(body, 'priority', TASK_PRIORITIES, errors)\n if (priority) values.priority = priority\n const status = readChoice(body, 'status', TASK_STATUSES, errors)\n if (status) values.status = status\n\n if (body.dueAt !== undefined) {\n if (body.dueAt === null) {\n values.dueAtMs = null\n } else {\n const ms = parseIsoInstant(body.dueAt)\n if (ms === null) {\n errors.dueAt = 'Must be an ISO 8601 instant, like 2026-09-10T15:00:00Z'\n } else {\n values.dueAtMs = ms\n }\n }\n }\n\n if (body.remindAt !== undefined) {\n if (body.remindAt === null) {\n values.remindAtMs = null\n } else {\n const ms = parseIsoInstant(body.remindAt)\n if (ms === null) {\n errors.remindAt = 'Must be an ISO 8601 instant, like 2026-09-10T14:00:00Z'\n } else {\n values.remindAtMs = ms\n }\n }\n }\n\n const assigneeUid = readOptionalText(body, 'assigneeUid', CRM_TITLE_MAX, errors)\n if (assigneeUid !== undefined) values.assigneeUid = assigneeUid\n for (const field of ['contactId', 'companyId', 'dealId'] as const) {\n const id = readRefId(body, field, errors)\n if (id !== undefined) values[field] = id\n }\n\n return Object.keys(errors).length ? { errors } : { values }\n}\n\nasync function taskRefErrors(\n ctx: ApiV1Context,\n values: TaskInput,\n): Promise<Record<string, string>> {\n const [assignee, refs] = await Promise.all([\n memberError(ctx, 'assigneeUid', values.assigneeUid),\n crmRefErrors(ctx, {\n contactId: values.contactId ?? undefined,\n companyId: values.companyId ?? undefined,\n dealId: values.dealId ?? undefined,\n }),\n ])\n return { ...assignee, ...refs }\n}\n\n/**\n * The records the task names carry `nextTaskAtMs` (AGL-2661), recomputed\n * after every write here from BOTH sides of the change. Its own catch: the\n * task write is done, and a figure that did not move is what the Fields\n * section's recompute is for, not a failed request.\n */\nasync function settleNextActivity(\n ctx: ApiV1Context,\n links: readonly (Record<string, unknown> | null | undefined)[],\n): Promise<void> {\n try {\n await recomputeCrmNextTaskAt(\n ctx.firestore,\n ctx.orgId,\n links.map((link) => crmNextActivityLinksOf(link)),\n )\n } catch (error) {\n console.error('[api-v1] next activity could not be recomputed', ctx.orgId, error)\n }\n}\n\n/** `POST /v1/tasks`. */\nasync function createTask(request: Request, ctx: ApiV1Context): Promise<Response> {\n const body = await readJsonBody(request)\n const parsed = readTaskInput(body, { partial: false })\n if ('errors' in parsed) return crmValidationFailed(ctx, 'task', parsed.errors)\n const site = readCrmSite(ctx, 'task', body)\n if ('response' in site) return site.response\n const refErrors = await taskRefErrors(ctx, parsed.values)\n if (Object.keys(refErrors).length) return crmValidationFailed(ctx, 'task', refErrors)\n\n const collection = crmCollection(ctx, CRM_COLLECTIONS.tasks)\n const claimed = await claimWrite(\n ctx,\n '*',\n request.headers.get('Idempotency-Key'),\n 'tasks',\n )\n if ('replay' in claimed) return claimed.replay\n const { claim } = claimed\n\n try {\n const { title, kind, priority, status, remindAtMs, ...rest } = parsed.values\n const id = createResourceUid()\n const stamp = crmCreateStamp(ctx, site.siteId)\n const record: Record<string, unknown> = {\n title,\n kind: kind ?? 'todo',\n priority: priority ?? 'normal',\n status: status ?? 'open',\n // A task created done was completed the instant it was created — the\n // same instant its `createdAt` carries.\n ...(status === 'done' ? { completedAtMs: stamp.createdAt.toMillis() } : {}),\n ...createPayload({\n ...rest,\n // A reminder on a task created done is owed to nobody.\n remindAtMs:\n status === 'done'\n ? null\n : crmTaskReminderAfterEdit({\n dueAtMs: rest.dueAtMs ?? null,\n remindAtMs,\n previous: null,\n }),\n }),\n /*\n * Stored as `null` when the body names none, never left absent: every\n * tasks list orders by `dueAtMs`, and Firestore leaves a document\n * without the ordered field out of the answer (AGL-3321).\n */\n dueAtMs: rest.dueAtMs ?? null,\n ...stamp,\n }\n // What the console's Tasks list searches by (AGL-3321).\n await collection.doc(id).create({ ...record, ...crmTaskListFields(record) })\n await settleNextActivity(ctx, [rest as Record<string, unknown>])\n const view = taskView(await collection.doc(id).get())\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/tasks/{id}`. */\nasync function updateTask(\n request: Request,\n ctx: ApiV1Context,\n ref: FirebaseFirestore.DocumentReference,\n): Promise<Response> {\n const parsed = readTaskInput(await readJsonBody(request), { partial: true })\n if ('errors' in parsed) return crmValidationFailed(ctx, 'task', parsed.errors)\n const snap = await ref.get()\n if (!snap.exists) {\n return ApiErrors.notFound({ message: 'No such task', headers: ctx.headers })\n }\n const refErrors = await taskRefErrors(ctx, parsed.values)\n if (Object.keys(refErrors).length) return crmValidationFailed(ctx, 'task', refErrors)\n\n const { status, remindAtMs, ...rest } = parsed.values\n const update: Record<string, unknown> = updatePayload(rest)\n // A cleared due date is stored `null`, not deleted — see the create.\n if (rest.dueAtMs === null) update.dueAtMs = null\n // One instant for the write: a task completed at T reads updated at T.\n const now = Timestamp.now()\n const completing = status === 'done' && status !== snap.get('status')\n if (status !== undefined && status !== snap.get('status')) {\n update.status = status\n update.completedAtMs = status === 'done' ? now.toMillis() : null\n }\n /*\n * The reminder the edit leaves: what the body said, else the rule over\n * the stored task and the due date this PATCH moves it to. Completion\n * clears one still owed. A reminder that MOVED — to a time or to none —\n * is one not yet sent, so the runner's mark comes off with it; one that\n * stayed keeps its mark.\n */\n const stored = snap.data() as Partial<CrmTask>\n const previous = {\n dueAtMs: typeof stored.dueAtMs === 'number' ? stored.dueAtMs : null,\n remindAtMs: typeof stored.remindAtMs === 'number' ? stored.remindAtMs : null,\n }\n const nextRemindAtMs =\n completing && crmTaskReminderPending(stored)\n ? null\n : crmTaskReminderAfterEdit({\n dueAtMs: rest.dueAtMs === undefined ? previous.dueAtMs : rest.dueAtMs,\n remindAtMs,\n previous,\n })\n if (nextRemindAtMs !== previous.remindAtMs) {\n update.remindAtMs = nextRemindAtMs === null ? FieldValue.delete() : nextRemindAtMs\n update.reminderSentAtMs = FieldValue.delete()\n }\n if (Object.keys(update).length > 0) {\n await ref.update({ ...update, updatedAt: now })\n await settleNextActivity(ctx, [snap.data(), rest as Record<string, unknown>])\n // What the console's Tasks list searches (AGL-3321).\n if ('title' in update) await restampCrmListFieldsAt(ref, 'crmTasks')\n }\n return apiJson(taskView(await ref.get()), { headers: ctx.headers })\n}\n\n/** `DELETE /v1/tasks/{id}`. */\nasync function deleteTask(\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 'task-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 task', headers: ctx.headers })\n }\n // Read before the delete: the records it named are recomputed without it.\n const named = snap.data()\n await ref.delete()\n await settleNextActivity(ctx, [named])\n const view = { id: ref.id, object: 'task', 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/** `GET /v1/tasks` filters, most selective first. */\nasync function listTasks(\n ctx: ApiV1Context,\n collection: FirebaseFirestore.CollectionReference,\n url: URL,\n): Promise<Response> {\n const rawStatus = url.searchParams.get('status')\n if (rawStatus !== null && rawStatus.trim() !== '' && !(TASK_STATUSES as readonly string[]).includes(rawStatus.trim())) {\n return crmValidationFailed(ctx, 'task filter', {\n status: `Must be one of: ${TASK_STATUSES.join(', ')}`,\n })\n }\n const filters = readEqualityFilters(url, [\n 'dealId',\n 'contactId',\n 'companyId',\n 'assigneeUid',\n 'status',\n ])\n return listCrm(ctx, collection, url, filters, taskView)\n}\n\nexport async function handleTasks(\n request: Request,\n ctx: ApiV1Context,\n segments: string[],\n url: URL,\n): Promise<Response> {\n const collection = crmCollection(ctx, CRM_COLLECTIONS.tasks)\n const [, taskId] = segments\n\n if (!taskId) {\n if (request.method === 'GET') {\n const denied = requireScope(ctx, 'crm:read')\n if (denied) return denied\n return listTasks(ctx, collection, url)\n }\n if (request.method === 'POST') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return createTask(request, ctx)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, POST' },\n })\n }\n\n const ref = collection.doc(taskId)\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 task', headers: ctx.headers })\n }\n return apiJson(taskView(snap), { headers: ctx.headers })\n }\n if (request.method === 'PATCH') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return updateTask(request, ctx, ref)\n }\n if (request.method === 'DELETE') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return deleteTask(request, ctx, ref)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, PATCH, DELETE' },\n })\n}\n"],"names":["CRM_COLLECTIONS","crmTaskReminderAfterEdit","crmTaskReminderPending","createResourceUid","crmTaskListFields","apiJson","ApiErrors","crmNextActivityLinksOf","recomputeCrmNextTaskAt","restampCrmListFieldsAt","FieldValue","Timestamp","claimWrite","readJsonBody","requireScope","CRM_TEXT_MAX","CRM_TITLE_MAX","createPayload","crmCollection","crmCreateStamp","crmRefErrors","crmTimes","crmValidationFailed","isoFromMs","listCrm","memberError","parseIsoInstant","readChoice","readCrmSite","readEqualityFilters","readOptionalText","readRefId","refuseUnknownKeys","updatePayload","TASK_KINDS","TASK_PRIORITIES","TASK_STATUSES","taskView","doc","data","id","object","title","notes","kind","priority","status","dueAt","dueAtMs","remindAt","remindAtMs","reminderSentAt","reminderSentAtMs","completedAt","completedAtMs","assigneeUid","contactId","companyId","dealId","siteId","hostId","TASK_WRITABLE","Set","readTaskInput","body","partial","errors","values","allowed","add","undefined","String","trim","slice","ms","field","Object","keys","length","taskRefErrors","ctx","assignee","refs","Promise","all","settleNextActivity","links","firestore","orgId","map","link","error","console","createTask","request","parsed","site","response","refErrors","collection","tasks","claimed","headers","get","replay","claim","rest","stamp","record","createdAt","toMillis","previous","create","view","release","updateTask","ref","snap","exists","notFound","message","update","now","completing","stored","nextRemindAtMs","delete","updatedAt","deleteTask","named","deleted","listTasks","url","rawStatus","searchParams","includes","join","filters","handleTasks","segments","taskId","method","denied","methodNotAllowed","Allow"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/plugins/crm/src/lib/server/api-v1/crm-tasks.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/tasks` (AGL-2606) — what the team owes a person: a call, an email, a\n * meeting or a to-do, with a due date, pointing at the contact, company or\n * deal it is for. A task may point at nothing — a plain to-do is still a\n * task — which is the one place it differs from an activity.\n *\n * `status` is the only state machine here and it has two states. Marking a\n * task `done` stamps `completedAtMs`; marking it `open` again clears it, so\n * a reopened task never reads as completed on the date it was first closed.\n *\n * `remindAt` (AGL-2659) is the task's reminder: the due time unless the\n * body names a time or `null`, carried along when a moved due date leaves\n * it behind, and cleared by completion while it is still owed — the rule\n * in `crmTaskReminderAfterEdit`, the same one the console's drawer keeps.\n * `reminderSentAt` is read-only: when the hourly runner handled it.\n *\n * `kind`, `priority` and `status` (AGL-3517) take a value of the org's\n * Type, Priority or Status picklist — its label, \"In Progress\" — or the\n * meaning behind it, `open`; the task stores both, and answers the meaning\n * under the field's own name with the label beside it as `typeLabel`,\n * `priorityLabel` and `statusLabel`.\n */\nimport {\n CRM_COLLECTIONS,\n CRM_TASK_PICKLIST_IDS,\n type CrmPicklistId,\n crmPicklistLabelForNew,\n type CrmTask,\n type CrmTaskKind,\n type CrmTaskPicklists,\n crmTaskPicklistLabels,\n type CrmTaskPriority,\n type CrmTaskStatus,\n createResourceUid,\n crmTaskListFields,\n resolveCrmSemanticPicklistWrite,\n} from '@aglyn/aglyn/server'\nimport {\n apiJson,\n ApiErrors,\n restampCrmListFieldsAt,\n} from '@aglyn/tenant-data-admin'\nimport { FieldValue, 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_TEXT_MAX,\n CRM_TITLE_MAX,\n createPayload,\n crmCollection,\n crmCreateStamp,\n crmRefErrors,\n crmTimes,\n crmValidationFailed,\n isoFromMs,\n listCrm,\n memberError,\n parseIsoInstant,\n readCrmSite,\n readEqualityFilters,\n readOptionalText,\n readRefId,\n refuseUnknownKeys,\n updatePayload,\n} from './crm-shared'\nimport { readCrmTaskPicklists } from '../read-picklist'\nimport { crmTaskReminderAfterEdit, crmTaskReminderPending } from '../../model/crm-task-reminders'\nimport { crmNextActivityLinksOf, recomputeCrmNextTaskAt } from '../crm-next-activity'\n\nconst TASK_STATUSES = ['open', 'done'] as const\n\n/** The org's task picklists, read once for a request. */\nconst taskPicklistsOf = (ctx: ApiV1Context): Promise<CrmTaskPicklists> =>\n readCrmTaskPicklists(ctx.firestore, ctx.orgId)\n\n/** The task object as published. Every writable field appears here. */\nfunction taskView(doc: FirebaseFirestore.DocumentSnapshot, picklists: CrmTaskPicklists) {\n const data = (doc.data() ?? {}) as Partial<CrmTask>\n const labels = crmTaskPicklistLabels(data, picklists)\n return {\n id: doc.id,\n object: 'task',\n title: data.title ?? null,\n notes: data.notes ?? null,\n kind: data.kind ?? 'todo',\n typeLabel: labels.type,\n priority: data.priority ?? 'normal',\n priorityLabel: labels.priority,\n status: data.status ?? 'open',\n statusLabel: labels.status,\n dueAt: isoFromMs(data.dueAtMs),\n remindAt: isoFromMs(data.remindAtMs),\n reminderSentAt: isoFromMs(data.reminderSentAtMs),\n completedAt: isoFromMs(data.completedAtMs),\n assigneeUid: data.assigneeUid ?? null,\n contactId: data.contactId ?? null,\n companyId: data.companyId ?? null,\n dealId: data.dealId ?? null,\n siteId: data.hostId ?? null,\n ...crmTimes(data as FirebaseFirestore.DocumentData),\n }\n}\n\nconst TASK_WRITABLE = new Set([\n 'title',\n 'notes',\n 'kind',\n 'priority',\n 'status',\n 'dueAt',\n 'remindAt',\n 'assigneeUid',\n 'contactId',\n 'companyId',\n 'dealId',\n])\n\n/** A picklist field as resolved: the meaning stored under its name, the label beside it. */\ninterface Picked<T extends string> {\n meaning: T\n label: string | null\n}\n\ninterface TaskInput {\n title?: string\n notes?: Clearable<string>\n kind?: Picked<CrmTaskKind>\n priority?: Picked<CrmTaskPriority>\n status?: Picked<CrmTaskStatus>\n dueAtMs?: Clearable<number>\n remindAtMs?: Clearable<number>\n assigneeUid?: Clearable<string>\n contactId?: Clearable<string>\n companyId?: Clearable<string>\n dealId?: Clearable<string>\n}\n\n/**\n * A Type, Priority or Status as the body names it — a label or a meaning —\n * against the org's list; the stored label is kept when the body names it\n * again. Absent answers `undefined`; anything the list does not hold is an\n * error naming the values it does.\n */\nfunction readPicklistField<T extends string>(\n body: Record<string, unknown>,\n key: 'kind' | 'priority' | 'status',\n id: CrmPicklistId,\n picklists: CrmTaskPicklists,\n stored: string | null | undefined,\n errors: Record<string, string>,\n): Picked<T> | undefined {\n const value = body[key]\n if (value === undefined) return undefined\n const list =\n key === 'kind' ? picklists.type : key === 'priority' ? picklists.priority : picklists.status\n const resolved =\n typeof value === 'string' ? resolveCrmSemanticPicklistWrite(id, list, value, stored) : null\n if (resolved?.ok) return { meaning: resolved.meaning as T, label: resolved.label }\n errors[key] =\n resolved?.ok === false ? resolved.error : 'Must be a value of the list, or its meaning'\n return undefined\n}\n\nfunction readTaskInput(\n body: Record<string, unknown>,\n { partial }: { partial: boolean },\n picklists: CrmTaskPicklists,\n stored: Partial<CrmTask> | null = null,\n): { values: TaskInput } | { errors: Record<string, string> } {\n const errors: Record<string, string> = {}\n const values: TaskInput = {}\n const allowed = new Set(TASK_WRITABLE)\n if (!partial) allowed.add('consentSiteId')\n refuseUnknownKeys(body, allowed, 'task', errors)\n\n if (body.title !== undefined || !partial) {\n const title = String(body.title ?? '')\n .trim()\n .slice(0, CRM_TITLE_MAX)\n if (title) values.title = title\n else errors.title = partial ? 'Must not be empty' : 'A title is required'\n }\n\n const notes = readOptionalText(body, 'notes', CRM_TEXT_MAX, errors)\n if (notes !== undefined) values.notes = notes\n const kind = readPicklistField<CrmTaskKind>(\n body, 'kind', CRM_TASK_PICKLIST_IDS.type, picklists, stored?.typeLabel, errors,\n )\n if (kind) values.kind = kind\n const priority = readPicklistField<CrmTaskPriority>(\n body, 'priority', CRM_TASK_PICKLIST_IDS.priority, picklists, stored?.priorityLabel, errors,\n )\n if (priority) values.priority = priority\n const status = readPicklistField<CrmTaskStatus>(\n body, 'status', CRM_TASK_PICKLIST_IDS.status, picklists, stored?.statusLabel, errors,\n )\n if (status) values.status = status\n\n if (body.dueAt !== undefined) {\n if (body.dueAt === null) {\n values.dueAtMs = null\n } else {\n const ms = parseIsoInstant(body.dueAt)\n if (ms === null) {\n errors.dueAt = 'Must be an ISO 8601 instant, like 2026-09-10T15:00:00Z'\n } else {\n values.dueAtMs = ms\n }\n }\n }\n\n if (body.remindAt !== undefined) {\n if (body.remindAt === null) {\n values.remindAtMs = null\n } else {\n const ms = parseIsoInstant(body.remindAt)\n if (ms === null) {\n errors.remindAt = 'Must be an ISO 8601 instant, like 2026-09-10T14:00:00Z'\n } else {\n values.remindAtMs = ms\n }\n }\n }\n\n const assigneeUid = readOptionalText(body, 'assigneeUid', CRM_TITLE_MAX, errors)\n if (assigneeUid !== undefined) values.assigneeUid = assigneeUid\n for (const field of ['contactId', 'companyId', 'dealId'] as const) {\n const id = readRefId(body, field, errors)\n if (id !== undefined) values[field] = id\n }\n\n return Object.keys(errors).length ? { errors } : { values }\n}\n\nasync function taskRefErrors(\n ctx: ApiV1Context,\n values: TaskInput,\n): Promise<Record<string, string>> {\n const [assignee, refs] = await Promise.all([\n memberError(ctx, 'assigneeUid', values.assigneeUid),\n crmRefErrors(ctx, {\n contactId: values.contactId ?? undefined,\n companyId: values.companyId ?? undefined,\n dealId: values.dealId ?? undefined,\n }),\n ])\n return { ...assignee, ...refs }\n}\n\n/**\n * The records the task names carry `nextTaskAtMs` (AGL-2661), recomputed\n * after every write here from BOTH sides of the change. Its own catch: the\n * task write is done, and a figure that did not move is what the Fields\n * section's recompute is for, not a failed request.\n */\nasync function settleNextActivity(\n ctx: ApiV1Context,\n links: readonly (Record<string, unknown> | null | undefined)[],\n): Promise<void> {\n try {\n await recomputeCrmNextTaskAt(\n ctx.firestore,\n ctx.orgId,\n links.map((link) => crmNextActivityLinksOf(link)),\n )\n } catch (error) {\n console.error('[api-v1] next activity could not be recomputed', ctx.orgId, error)\n }\n}\n\n/** `POST /v1/tasks`. */\nasync function createTask(request: Request, ctx: ApiV1Context): Promise<Response> {\n const body = await readJsonBody(request)\n const picklists = await taskPicklistsOf(ctx)\n const parsed = readTaskInput(body, { partial: false }, picklists)\n if ('errors' in parsed) return crmValidationFailed(ctx, 'task', parsed.errors)\n const site = readCrmSite(ctx, 'task', body)\n if ('response' in site) return site.response\n const refErrors = await taskRefErrors(ctx, parsed.values)\n if (Object.keys(refErrors).length) return crmValidationFailed(ctx, 'task', refErrors)\n\n const collection = crmCollection(ctx, CRM_COLLECTIONS.tasks)\n const claimed = await claimWrite(\n ctx,\n '*',\n request.headers.get('Idempotency-Key'),\n 'tasks',\n )\n if ('replay' in claimed) return claimed.replay\n const { claim } = claimed\n\n try {\n const { title, kind: pickedKind, priority: pickedPriority, status: pickedStatus, remindAtMs, ...rest } =\n parsed.values\n const kind = pickedKind?.meaning ?? 'todo'\n const priority = pickedPriority?.meaning ?? 'normal'\n const status = pickedStatus?.meaning ?? 'open'\n const id = createResourceUid()\n const stamp = crmCreateStamp(ctx, site.siteId)\n const record: Record<string, unknown> = {\n title,\n // Each meaning with the org's label beside it (AGL-3517).\n kind,\n typeLabel: pickedKind ? pickedKind.label : crmPicklistLabelForNew(picklists.type, kind),\n priority,\n priorityLabel: pickedPriority\n ? pickedPriority.label\n : crmPicklistLabelForNew(picklists.priority, priority),\n status,\n statusLabel: pickedStatus\n ? pickedStatus.label\n : crmPicklistLabelForNew(picklists.status, status),\n // A task created done was completed the instant it was created — the\n // same instant its `createdAt` carries.\n ...(status === 'done' ? { completedAtMs: stamp.createdAt.toMillis() } : {}),\n ...createPayload({\n ...rest,\n // A reminder on a task created done is owed to nobody.\n remindAtMs:\n status === 'done'\n ? null\n : crmTaskReminderAfterEdit({\n dueAtMs: rest.dueAtMs ?? null,\n remindAtMs,\n previous: null,\n }),\n }),\n /*\n * Stored as `null` when the body names none, never left absent: every\n * tasks list orders by `dueAtMs`, and Firestore leaves a document\n * without the ordered field out of the answer (AGL-3321).\n */\n dueAtMs: rest.dueAtMs ?? null,\n ...stamp,\n }\n // What the console's Tasks list searches by (AGL-3321).\n await collection.doc(id).create({ ...record, ...crmTaskListFields(record) })\n await settleNextActivity(ctx, [rest as Record<string, unknown>])\n const view = taskView(await collection.doc(id).get(), picklists)\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/tasks/{id}`. */\nasync function updateTask(\n request: Request,\n ctx: ApiV1Context,\n ref: FirebaseFirestore.DocumentReference,\n): Promise<Response> {\n const body = await readJsonBody(request)\n const snap = await ref.get()\n if (!snap.exists) {\n return ApiErrors.notFound({ message: 'No such task', headers: ctx.headers })\n }\n const picklists = await taskPicklistsOf(ctx)\n const parsed = readTaskInput(body, { partial: true }, picklists, snap.data() as Partial<CrmTask>)\n if ('errors' in parsed) return crmValidationFailed(ctx, 'task', parsed.errors)\n const refErrors = await taskRefErrors(ctx, parsed.values)\n if (Object.keys(refErrors).length) return crmValidationFailed(ctx, 'task', refErrors)\n\n const { status: pickedStatus, kind: pickedKind, priority: pickedPriority, remindAtMs, ...rest } =\n parsed.values\n const update: Record<string, unknown> = updatePayload(rest)\n // Each meaning with the org's label beside it (AGL-3517).\n if (pickedKind) {\n update.kind = pickedKind.meaning\n update.typeLabel = pickedKind.label\n }\n if (pickedPriority) {\n update.priority = pickedPriority.meaning\n update.priorityLabel = pickedPriority.label\n }\n // A cleared due date is stored `null`, not deleted — see the create.\n if (rest.dueAtMs === null) update.dueAtMs = null\n // One instant for the write: a task completed at T reads updated at T.\n const now = Timestamp.now()\n const status = pickedStatus?.meaning\n const completing = status === 'done' && status !== snap.get('status')\n if (pickedStatus) update.statusLabel = pickedStatus.label\n if (status !== undefined && status !== snap.get('status')) {\n update.status = status\n update.completedAtMs = status === 'done' ? now.toMillis() : null\n }\n /*\n * The reminder the edit leaves: what the body said, else the rule over\n * the stored task and the due date this PATCH moves it to. Completion\n * clears one still owed. A reminder that MOVED — to a time or to none —\n * is one not yet sent, so the runner's mark comes off with it; one that\n * stayed keeps its mark.\n */\n const stored = snap.data() as Partial<CrmTask>\n const previous = {\n dueAtMs: typeof stored.dueAtMs === 'number' ? stored.dueAtMs : null,\n remindAtMs: typeof stored.remindAtMs === 'number' ? stored.remindAtMs : null,\n }\n const nextRemindAtMs =\n completing && crmTaskReminderPending(stored)\n ? null\n : crmTaskReminderAfterEdit({\n dueAtMs: rest.dueAtMs === undefined ? previous.dueAtMs : rest.dueAtMs,\n remindAtMs,\n previous,\n })\n if (nextRemindAtMs !== previous.remindAtMs) {\n update.remindAtMs = nextRemindAtMs === null ? FieldValue.delete() : nextRemindAtMs\n update.reminderSentAtMs = FieldValue.delete()\n }\n if (Object.keys(update).length > 0) {\n await ref.update({ ...update, updatedAt: now })\n await settleNextActivity(ctx, [snap.data(), rest as Record<string, unknown>])\n // What the console's Tasks list searches (AGL-3321).\n if ('title' in update) await restampCrmListFieldsAt(ref, 'crmTasks')\n }\n return apiJson(taskView(await ref.get(), picklists), { headers: ctx.headers })\n}\n\n/** `DELETE /v1/tasks/{id}`. */\nasync function deleteTask(\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 'task-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 task', headers: ctx.headers })\n }\n // Read before the delete: the records it named are recomputed without it.\n const named = snap.data()\n await ref.delete()\n await settleNextActivity(ctx, [named])\n const view = { id: ref.id, object: 'task', 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/** `GET /v1/tasks` filters, most selective first. */\nasync function listTasks(\n ctx: ApiV1Context,\n collection: FirebaseFirestore.CollectionReference,\n url: URL,\n): Promise<Response> {\n const rawStatus = url.searchParams.get('status')\n if (rawStatus !== null && rawStatus.trim() !== '' && !(TASK_STATUSES as readonly string[]).includes(rawStatus.trim())) {\n return crmValidationFailed(ctx, 'task filter', {\n status: `Must be one of: ${TASK_STATUSES.join(', ')}`,\n })\n }\n const filters = readEqualityFilters(url, [\n 'dealId',\n 'contactId',\n 'companyId',\n 'assigneeUid',\n 'status',\n ])\n const picklists = await taskPicklistsOf(ctx)\n return listCrm(ctx, collection, url, filters, (doc) => taskView(doc, picklists))\n}\n\nexport async function handleTasks(\n request: Request,\n ctx: ApiV1Context,\n segments: string[],\n url: URL,\n): Promise<Response> {\n const collection = crmCollection(ctx, CRM_COLLECTIONS.tasks)\n const [, taskId] = segments\n\n if (!taskId) {\n if (request.method === 'GET') {\n const denied = requireScope(ctx, 'crm:read')\n if (denied) return denied\n return listTasks(ctx, collection, url)\n }\n if (request.method === 'POST') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return createTask(request, ctx)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, POST' },\n })\n }\n\n const ref = collection.doc(taskId)\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 task', headers: ctx.headers })\n }\n return apiJson(taskView(snap, await taskPicklistsOf(ctx)), { headers: ctx.headers })\n }\n if (request.method === 'PATCH') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return updateTask(request, ctx, ref)\n }\n if (request.method === 'DELETE') {\n const denied = requireScope(ctx, 'crm:write')\n if (denied) return denied\n return deleteTask(request, ctx, ref)\n }\n return ApiErrors.methodNotAllowed({\n headers: { ...ctx.headers, Allow: 'GET, PATCH, DELETE' },\n })\n}\n"],"names":["CRM_COLLECTIONS","CRM_TASK_PICKLIST_IDS","crmPicklistLabelForNew","crmTaskPicklistLabels","createResourceUid","crmTaskListFields","resolveCrmSemanticPicklistWrite","apiJson","ApiErrors","restampCrmListFieldsAt","FieldValue","Timestamp","claimWrite","readJsonBody","requireScope","CRM_TEXT_MAX","CRM_TITLE_MAX","createPayload","crmCollection","crmCreateStamp","crmRefErrors","crmTimes","crmValidationFailed","isoFromMs","listCrm","memberError","parseIsoInstant","readCrmSite","readEqualityFilters","readOptionalText","readRefId","refuseUnknownKeys","updatePayload","readCrmTaskPicklists","crmTaskReminderAfterEdit","crmTaskReminderPending","crmNextActivityLinksOf","recomputeCrmNextTaskAt","TASK_STATUSES","taskPicklistsOf","ctx","firestore","orgId","taskView","doc","picklists","data","labels","id","object","title","notes","kind","typeLabel","type","priority","priorityLabel","status","statusLabel","dueAt","dueAtMs","remindAt","remindAtMs","reminderSentAt","reminderSentAtMs","completedAt","completedAtMs","assigneeUid","contactId","companyId","dealId","siteId","hostId","TASK_WRITABLE","Set","readPicklistField","body","key","stored","errors","value","undefined","list","resolved","ok","meaning","label","error","readTaskInput","partial","values","allowed","add","String","trim","slice","ms","field","Object","keys","length","taskRefErrors","assignee","refs","Promise","all","settleNextActivity","links","map","link","console","createTask","request","parsed","site","response","refErrors","collection","tasks","claimed","headers","get","replay","claim","rest","pickedKind","pickedPriority","pickedStatus","stamp","record","createdAt","toMillis","previous","create","view","release","updateTask","ref","snap","exists","notFound","message","update","now","completing","nextRemindAtMs","delete","updatedAt","deleteTask","named","deleted","listTasks","url","rawStatus","searchParams","includes","join","filters","handleTasks","segments","taskId","method","denied","methodNotAllowed","Allow"],"mappings":"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"}
|
|
@@ -15,15 +15,4 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import { type ApiV1ResourceDescription } from '@aglyn/tenant-data-admin/server/api-v1-description';
|
|
18
|
-
/**
|
|
19
|
-
* The CRM's resources as the customer API's OpenAPI document describes them
|
|
20
|
-
* (AGL-2733), keyed by the resource each describes — what the console's
|
|
21
|
-
* builder turns into their paths, tags and schemas, and the MCP tools derive
|
|
22
|
-
* from.
|
|
23
|
-
*
|
|
24
|
-
* Transcribed from the response examples in `apps/docs/api/resources/*.md`,
|
|
25
|
-
* the customer-facing contract, as the platform's own resources are; each
|
|
26
|
-
* write body lists its handler's own writable set. `api-v1-openapi.spec.ts`
|
|
27
|
-
* holds the document to every endpoint the documentation promises.
|
|
28
|
-
*/
|
|
29
18
|
export declare const CRM_API_V1_DESCRIPTIONS: Readonly<Record<string, ApiV1ResourceDescription>>;
|