diff --git a/crm/api/__init__.py b/crm/api/__init__.py index 58739de0..f0dcf649 100644 --- a/crm/api/__init__.py +++ b/crm/api/__init__.py @@ -44,7 +44,7 @@ def get_user_signature(): if html_signature: _signature = html_signature.renderContents() content = "" - if (cstr(_signature) or signature): + if cstr(_signature) or signature: content = f'

{signature}

' return content @@ -64,14 +64,16 @@ def check_app_permission(): return True roles = frappe.get_roles() - if any(role in ["System Manager", "Sales User", "Sales Manager", "Sales Master Manager"] for role in roles): + if any( + role in ["System Manager", "Sales User", "Sales Manager", "Sales Master Manager"] for role in roles + ): return True return False @frappe.whitelist(allow_guest=True) -def accept_invitation(key: str = None): +def accept_invitation(key: str | None = None): if not key: frappe.throw("Invalid or expired key") @@ -91,6 +93,7 @@ def accept_invitation(key: str = None): @frappe.whitelist() def invite_by_email(emails: str, role: str): + frappe.only_for("Sales Manager") if not emails: return email_string = validate_email_address(emails, throw=False) @@ -120,8 +123,8 @@ def get_file_uploader_defaults(doctype: str): make_attachments_public = meta.get("make_attachments_public") return { - 'allowed_file_types': frappe.get_system_settings("allowed_file_extensions"), - 'max_file_size': get_max_file_size(), - 'max_number_of_files': max_number_of_files, - 'make_attachments_public': bool(make_attachments_public), - } \ No newline at end of file + "allowed_file_types": frappe.get_system_settings("allowed_file_extensions"), + "max_file_size": get_max_file_size(), + "max_number_of_files": max_number_of_files, + "make_attachments_public": bool(make_attachments_public), + } diff --git a/crm/api/onboarding.py b/crm/api/onboarding.py new file mode 100644 index 00000000..00d27b07 --- /dev/null +++ b/crm/api/onboarding.py @@ -0,0 +1,24 @@ +import frappe + + +@frappe.whitelist() +def get_first_lead(): + lead = frappe.get_all( + "CRM Lead", + filters={"converted": 0}, + fields=["name"], + order_by="creation", + limit=1, + ) + return lead[0].name if lead else None + + +@frappe.whitelist() +def get_first_deal(): + deal = frappe.get_all( + "CRM Deal", + fields=["name"], + order_by="creation", + limit=1, + ) + return deal[0].name if deal else None diff --git a/frappe-ui b/frappe-ui index 33c9907a..b6efd25b 160000 --- a/frappe-ui +++ b/frappe-ui @@ -1 +1 @@ -Subproject commit 33c9907aa9163d8d3b84f23dc2a2c829e4d8c6f1 +Subproject commit b6efd25b2122c2c1f3beeea1702788c5e6e5555f diff --git a/frontend/components.d.ts b/frontend/components.d.ts new file mode 100644 index 00000000..081f1074 --- /dev/null +++ b/frontend/components.d.ts @@ -0,0 +1,229 @@ +/* eslint-disable */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +// biome-ignore lint: disable +export {} + +/* prettier-ignore */ +declare module 'vue' { + export interface GlobalComponents { + Activities: typeof import('./src/components/Activities/Activities.vue')['default'] + ActivityHeader: typeof import('./src/components/Activities/ActivityHeader.vue')['default'] + ActivityIcon: typeof import('./src/components/Icons/ActivityIcon.vue')['default'] + AddressIcon: typeof import('./src/components/Icons/AddressIcon.vue')['default'] + AddressModal: typeof import('./src/components/Modals/AddressModal.vue')['default'] + AllModals: typeof import('./src/components/Activities/AllModals.vue')['default'] + AppHeader: typeof import('./src/components/Layouts/AppHeader.vue')['default'] + Apps: typeof import('./src/components/Apps.vue')['default'] + AppsIcon: typeof import('./src/components/Icons/AppsIcon.vue')['default'] + AppSidebar: typeof import('./src/components/Layouts/AppSidebar.vue')['default'] + ArrowUpRightIcon: typeof import('./src/components/Icons/ArrowUpRightIcon.vue')['default'] + AscendingIcon: typeof import('./src/components/Icons/AscendingIcon.vue')['default'] + AssignmentModal: typeof import('./src/components/Modals/AssignmentModal.vue')['default'] + AssignTo: typeof import('./src/components/AssignTo.vue')['default'] + AttachmentArea: typeof import('./src/components/Activities/AttachmentArea.vue')['default'] + AttachmentIcon: typeof import('./src/components/Icons/AttachmentIcon.vue')['default'] + AttachmentItem: typeof import('./src/components/AttachmentItem.vue')['default'] + AudioPlayer: typeof import('./src/components/Activities/AudioPlayer.vue')['default'] + Autocomplete: typeof import('./src/components/frappe-ui/Autocomplete.vue')['default'] + AvatarIcon: typeof import('./src/components/Icons/AvatarIcon.vue')['default'] + BrandLogo: typeof import('./src/components/BrandLogo.vue')['default'] + CalendarIcon: typeof import('./src/components/Icons/CalendarIcon.vue')['default'] + CallArea: typeof import('./src/components/Activities/CallArea.vue')['default'] + CallLogDetailModal: typeof import('./src/components/Modals/CallLogDetailModal.vue')['default'] + CallLogModal: typeof import('./src/components/Modals/CallLogModal.vue')['default'] + CallLogsListView: typeof import('./src/components/ListViews/CallLogsListView.vue')['default'] + CallUI: typeof import('./src/components/Telephony/CallUI.vue')['default'] + CameraIcon: typeof import('./src/components/Icons/CameraIcon.vue')['default'] + CertificateIcon: typeof import('./src/components/Icons/CertificateIcon.vue')['default'] + CheckCircleIcon: typeof import('./src/components/Icons/CheckCircleIcon.vue')['default'] + CheckIcon: typeof import('./src/components/Icons/CheckIcon.vue')['default'] + CollapseSidebar: typeof import('./src/components/Icons/CollapseSidebar.vue')['default'] + Column: typeof import('./src/components/FieldLayout/Column.vue')['default'] + ColumnSettings: typeof import('./src/components/ColumnSettings.vue')['default'] + ColumnsIcon: typeof import('./src/components/Icons/ColumnsIcon.vue')['default'] + CommentArea: typeof import('./src/components/Activities/CommentArea.vue')['default'] + CommentBox: typeof import('./src/components/CommentBox.vue')['default'] + CommentIcon: typeof import('./src/components/Icons/CommentIcon.vue')['default'] + CommunicationArea: typeof import('./src/components/CommunicationArea.vue')['default'] + ContactIcon: typeof import('./src/components/Icons/ContactIcon.vue')['default'] + ContactModal: typeof import('./src/components/Modals/ContactModal.vue')['default'] + ContactsIcon: typeof import('./src/components/Icons/ContactsIcon.vue')['default'] + ContactsListView: typeof import('./src/components/ListViews/ContactsListView.vue')['default'] + ConvertIcon: typeof import('./src/components/Icons/ConvertIcon.vue')['default'] + CountUpTimer: typeof import('./src/components/CountUpTimer.vue')['default'] + CRMLogo: typeof import('./src/components/Icons/CRMLogo.vue')['default'] + CustomActions: typeof import('./src/components/CustomActions.vue')['default'] + DashboardIcon: typeof import('./src/components/Icons/DashboardIcon.vue')['default'] + DataFields: typeof import('./src/components/Activities/DataFields.vue')['default'] + DataFieldsModal: typeof import('./src/components/Modals/DataFieldsModal.vue')['default'] + DealModal: typeof import('./src/components/Modals/DealModal.vue')['default'] + DealsIcon: typeof import('./src/components/Icons/DealsIcon.vue')['default'] + DealsListView: typeof import('./src/components/ListViews/DealsListView.vue')['default'] + DeclinedCallIcon: typeof import('./src/components/Icons/DeclinedCallIcon.vue')['default'] + DesendingIcon: typeof import('./src/components/Icons/DesendingIcon.vue')['default'] + DesktopLayout: typeof import('./src/components/Layouts/DesktopLayout.vue')['default'] + DetailsIcon: typeof import('./src/components/Icons/DetailsIcon.vue')['default'] + DialpadIcon: typeof import('./src/components/Icons/DialpadIcon.vue')['default'] + DocumentIcon: typeof import('./src/components/Icons/DocumentIcon.vue')['default'] + DotIcon: typeof import('./src/components/Icons/DotIcon.vue')['default'] + DoubleCheckIcon: typeof import('./src/components/Icons/DoubleCheckIcon.vue')['default'] + DragIcon: typeof import('./src/components/Icons/DragIcon.vue')['default'] + DragVerticalIcon: typeof import('./src/components/Icons/DragVerticalIcon.vue')['default'] + Dropdown: typeof import('./src/components/frappe-ui/Dropdown.vue')['default'] + DropdownItem: typeof import('./src/components/DropdownItem.vue')['default'] + DuplicateIcon: typeof import('./src/components/Icons/DuplicateIcon.vue')['default'] + DurationIcon: typeof import('./src/components/Icons/DurationIcon.vue')['default'] + EditIcon: typeof import('./src/components/Icons/EditIcon.vue')['default'] + EditValueModal: typeof import('./src/components/Modals/EditValueModal.vue')['default'] + Email2Icon: typeof import('./src/components/Icons/Email2Icon.vue')['default'] + EmailArea: typeof import('./src/components/Activities/EmailArea.vue')['default'] + EmailAtIcon: typeof import('./src/components/Icons/EmailAtIcon.vue')['default'] + EmailContent: typeof import('./src/components/Activities/EmailContent.vue')['default'] + EmailEditor: typeof import('./src/components/EmailEditor.vue')['default'] + EmailIcon: typeof import('./src/components/Icons/EmailIcon.vue')['default'] + EmailTemplateModal: typeof import('./src/components/Modals/EmailTemplateModal.vue')['default'] + EmailTemplateSelectorModal: typeof import('./src/components/Modals/EmailTemplateSelectorModal.vue')['default'] + EmailTemplatesListView: typeof import('./src/components/ListViews/EmailTemplatesListView.vue')['default'] + ERPNextIcon: typeof import('./src/components/Icons/ERPNextIcon.vue')['default'] + ERPNextSettings: typeof import('./src/components/Settings/ERPNextSettings.vue')['default'] + ExotelCallUI: typeof import('./src/components/Telephony/ExotelCallUI.vue')['default'] + ExportIcon: typeof import('./src/components/Icons/ExportIcon.vue')['default'] + ExternalLinkIcon: typeof import('./src/components/Icons/ExternalLinkIcon.vue')['default'] + FadedScrollableDiv: typeof import('./src/components/FadedScrollableDiv.vue')['default'] + Field: typeof import('./src/components/FieldLayout/Field.vue')['default'] + FieldLayout: typeof import('./src/components/FieldLayout/FieldLayout.vue')['default'] + FieldLayoutEditor: typeof import('./src/components/FieldLayoutEditor.vue')['default'] + FileAudioIcon: typeof import('./src/components/Icons/FileAudioIcon.vue')['default'] + FileIcon: typeof import('./src/components/Icons/FileIcon.vue')['default'] + FileImageIcon: typeof import('./src/components/Icons/FileImageIcon.vue')['default'] + FileSpreadsheetIcon: typeof import('./src/components/Icons/FileSpreadsheetIcon.vue')['default'] + FilesUploader: typeof import('./src/components/FilesUploader/FilesUploader.vue')['default'] + FilesUploaderArea: typeof import('./src/components/FilesUploader/FilesUploaderArea.vue')['default'] + FileTextIcon: typeof import('./src/components/Icons/FileTextIcon.vue')['default'] + FileTypeIcon: typeof import('./src/components/Icons/FileTypeIcon.vue')['default'] + FileVideoIcon: typeof import('./src/components/Icons/FileVideoIcon.vue')['default'] + Filter: typeof import('./src/components/Filter.vue')['default'] + FilterIcon: typeof import('./src/components/Icons/FilterIcon.vue')['default'] + FrappeCloudIcon: typeof import('./src/components/Icons/FrappeCloudIcon.vue')['default'] + GenderIcon: typeof import('./src/components/Icons/GenderIcon.vue')['default'] + GeneralSettings: typeof import('./src/components/Settings/GeneralSettings.vue')['default'] + GoogleIcon: typeof import('./src/components/Icons/GoogleIcon.vue')['default'] + Grid: typeof import('./src/components/Controls/Grid.vue')['default'] + GridFieldsEditorModal: typeof import('./src/components/Controls/GridFieldsEditorModal.vue')['default'] + GridRowFieldsModal: typeof import('./src/components/Controls/GridRowFieldsModal.vue')['default'] + GridRowModal: typeof import('./src/components/Controls/GridRowModal.vue')['default'] + GroupBy: typeof import('./src/components/GroupBy.vue')['default'] + GroupByIcon: typeof import('./src/components/Icons/GroupByIcon.vue')['default'] + HeartIcon: typeof import('./src/components/Icons/HeartIcon.vue')['default'] + HelpIcon: typeof import('./src/components/Icons/HelpIcon.vue')['default'] + Icon: typeof import('./src/components/Icon.vue')['default'] + IconPicker: typeof import('./src/components/IconPicker.vue')['default'] + ImageUploader: typeof import('./src/components/Controls/ImageUploader.vue')['default'] + InboundCallIcon: typeof import('./src/components/Icons/InboundCallIcon.vue')['default'] + InboxIcon: typeof import('./src/components/Icons/InboxIcon.vue')['default'] + IndicatorIcon: typeof import('./src/components/Icons/IndicatorIcon.vue')['default'] + InviteIcon: typeof import('./src/components/Icons/InviteIcon.vue')['default'] + InviteMemberPage: typeof import('./src/components/Settings/InviteMemberPage.vue')['default'] + KanbanIcon: typeof import('./src/components/Icons/KanbanIcon.vue')['default'] + KanbanSettings: typeof import('./src/components/Kanban/KanbanSettings.vue')['default'] + KanbanView: typeof import('./src/components/Kanban/KanbanView.vue')['default'] + LayoutHeader: typeof import('./src/components/LayoutHeader.vue')['default'] + LeadModal: typeof import('./src/components/Modals/LeadModal.vue')['default'] + LeadsIcon: typeof import('./src/components/Icons/LeadsIcon.vue')['default'] + LeadsListView: typeof import('./src/components/ListViews/LeadsListView.vue')['default'] + LightningIcon: typeof import('./src/components/Icons/LightningIcon.vue')['default'] + Link: typeof import('./src/components/Controls/Link.vue')['default'] + LinkIcon: typeof import('./src/components/Icons/LinkIcon.vue')['default'] + ListBulkActions: typeof import('./src/components/ListBulkActions.vue')['default'] + ListIcon: typeof import('./src/components/Icons/ListIcon.vue')['default'] + ListRows: typeof import('./src/components/ListViews/ListRows.vue')['default'] + LoadingIndicator: typeof import('./src/components/Icons/LoadingIndicator.vue')['default'] + MarkAsDoneIcon: typeof import('./src/components/Icons/MarkAsDoneIcon.vue')['default'] + MaximizeIcon: typeof import('./src/components/Icons/MaximizeIcon.vue')['default'] + MenuIcon: typeof import('./src/components/Icons/MenuIcon.vue')['default'] + MinimizeIcon: typeof import('./src/components/Icons/MinimizeIcon.vue')['default'] + MissedCallIcon: typeof import('./src/components/Icons/MissedCallIcon.vue')['default'] + MobileAppHeader: typeof import('./src/components/Mobile/MobileAppHeader.vue')['default'] + MobileLayout: typeof import('./src/components/Layouts/MobileLayout.vue')['default'] + MobileSidebar: typeof import('./src/components/Mobile/MobileSidebar.vue')['default'] + MoneyIcon: typeof import('./src/components/Icons/MoneyIcon.vue')['default'] + MultipleAvatar: typeof import('./src/components/MultipleAvatar.vue')['default'] + MultiselectInput: typeof import('./src/components/Controls/MultiselectInput.vue')['default'] + MultiValueInput: typeof import('./src/components/Controls/MultiValueInput.vue')['default'] + MuteIcon: typeof import('./src/components/Icons/MuteIcon.vue')['default'] + NestedPopover: typeof import('./src/components/NestedPopover.vue')['default'] + NoteArea: typeof import('./src/components/Activities/NoteArea.vue')['default'] + NoteIcon: typeof import('./src/components/Icons/NoteIcon.vue')['default'] + NoteModal: typeof import('./src/components/Modals/NoteModal.vue')['default'] + Notifications: typeof import('./src/components/Notifications.vue')['default'] + NotificationsIcon: typeof import('./src/components/Icons/NotificationsIcon.vue')['default'] + OrganizationModal: typeof import('./src/components/Modals/OrganizationModal.vue')['default'] + OrganizationsIcon: typeof import('./src/components/Icons/OrganizationsIcon.vue')['default'] + OrganizationsListView: typeof import('./src/components/ListViews/OrganizationsListView.vue')['default'] + OutboundCallIcon: typeof import('./src/components/Icons/OutboundCallIcon.vue')['default'] + PauseIcon: typeof import('./src/components/Icons/PauseIcon.vue')['default'] + PhoneIcon: typeof import('./src/components/Icons/PhoneIcon.vue')['default'] + PinIcon: typeof import('./src/components/Icons/PinIcon.vue')['default'] + PlaybackSpeedIcon: typeof import('./src/components/Icons/PlaybackSpeedIcon.vue')['default'] + PlaybackSpeedOption: typeof import('./src/components/Activities/PlaybackSpeedOption.vue')['default'] + PlayIcon: typeof import('./src/components/Icons/PlayIcon.vue')['default'] + Popover: typeof import('./src/components/frappe-ui/Popover.vue')['default'] + ProfileImageEditor: typeof import('./src/components/Settings/ProfileImageEditor.vue')['default'] + ProfileSettings: typeof import('./src/components/Settings/ProfileSettings.vue')['default'] + QuickEntryModal: typeof import('./src/components/Modals/QuickEntryModal.vue')['default'] + QuickFilterField: typeof import('./src/components/QuickFilterField.vue')['default'] + QuickFilterIcon: typeof import('./src/components/Icons/QuickFilterIcon.vue')['default'] + ReactIcon: typeof import('./src/components/Icons/ReactIcon.vue')['default'] + RefreshIcon: typeof import('./src/components/Icons/RefreshIcon.vue')['default'] + ReloadIcon: typeof import('./src/components/Icons/ReloadIcon.vue')['default'] + ReplyAllIcon: typeof import('./src/components/Icons/ReplyAllIcon.vue')['default'] + ReplyIcon: typeof import('./src/components/Icons/ReplyIcon.vue')['default'] + Resizer: typeof import('./src/components/Resizer.vue')['default'] + RightSideLayoutIcon: typeof import('./src/components/Icons/RightSideLayoutIcon.vue')['default'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + Section: typeof import('./src/components/FieldLayout/Section.vue')['default'] + SelectIcon: typeof import('./src/components/Icons/SelectIcon.vue')['default'] + Settings: typeof import('./src/components/Settings/Settings.vue')['default'] + SettingsIcon: typeof import('./src/components/Icons/SettingsIcon.vue')['default'] + SettingsPage: typeof import('./src/components/Settings/SettingsPage.vue')['default'] + SidebarLink: typeof import('./src/components/SidebarLink.vue')['default'] + SidePanelLayout: typeof import('./src/components/SidePanelLayout.vue')['default'] + SidePanelLayoutEditor: typeof import('./src/components/SidePanelLayoutEditor.vue')['default'] + SidePanelModal: typeof import('./src/components/Modals/SidePanelModal.vue')['default'] + SignupBanner: typeof import('./src/components/SignupBanner.vue')['default'] + SLASection: typeof import('./src/components/SLASection.vue')['default'] + SmileIcon: typeof import('./src/components/Icons/SmileIcon.vue')['default'] + SortBy: typeof import('./src/components/SortBy.vue')['default'] + SortIcon: typeof import('./src/components/Icons/SortIcon.vue')['default'] + StepsIcon: typeof import('./src/components/Icons/StepsIcon.vue')['default'] + SuccessIcon: typeof import('./src/components/Icons/SuccessIcon.vue')['default'] + TableMultiselectInput: typeof import('./src/components/Controls/TableMultiselectInput.vue')['default'] + TaskArea: typeof import('./src/components/Activities/TaskArea.vue')['default'] + TaskIcon: typeof import('./src/components/Icons/TaskIcon.vue')['default'] + TaskModal: typeof import('./src/components/Modals/TaskModal.vue')['default'] + TaskPanel: typeof import('./src/components/Telephony/TaskPanel.vue')['default'] + TaskPriorityIcon: typeof import('./src/components/Icons/TaskPriorityIcon.vue')['default'] + TasksListView: typeof import('./src/components/ListViews/TasksListView.vue')['default'] + TaskStatusIcon: typeof import('./src/components/Icons/TaskStatusIcon.vue')['default'] + TelephonySettings: typeof import('./src/components/Settings/TelephonySettings.vue')['default'] + TerritoryIcon: typeof import('./src/components/Icons/TerritoryIcon.vue')['default'] + TwilioCallUI: typeof import('./src/components/Telephony/TwilioCallUI.vue')['default'] + UnpinIcon: typeof import('./src/components/Icons/UnpinIcon.vue')['default'] + UserAvatar: typeof import('./src/components/UserAvatar.vue')['default'] + UserDropdown: typeof import('./src/components/UserDropdown.vue')['default'] + ViewBreadcrumbs: typeof import('./src/components/ViewBreadcrumbs.vue')['default'] + ViewControls: typeof import('./src/components/ViewControls.vue')['default'] + ViewModal: typeof import('./src/components/Modals/ViewModal.vue')['default'] + VolumnHighIcon: typeof import('./src/components/Icons/VolumnHighIcon.vue')['default'] + VolumnLowIcon: typeof import('./src/components/Icons/VolumnLowIcon.vue')['default'] + WebsiteIcon: typeof import('./src/components/Icons/WebsiteIcon.vue')['default'] + WhatsAppArea: typeof import('./src/components/Activities/WhatsAppArea.vue')['default'] + WhatsAppBox: typeof import('./src/components/Activities/WhatsAppBox.vue')['default'] + WhatsAppIcon: typeof import('./src/components/Icons/WhatsAppIcon.vue')['default'] + WhatsAppSettings: typeof import('./src/components/Settings/WhatsAppSettings.vue')['default'] + WhatsappTemplateSelectorModal: typeof import('./src/components/Modals/WhatsappTemplateSelectorModal.vue')['default'] + } +} diff --git a/frontend/package.json b/frontend/package.json index bb53389b..37c2025e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,7 +14,7 @@ "@vueuse/core": "^10.3.0", "@vueuse/integrations": "^10.3.0", "feather-icons": "^4.28.0", - "frappe-ui": "^0.1.111", + "frappe-ui": "^0.1.118", "gemoji": "^8.1.0", "lodash": "^4.17.21", "mime": "^4.0.1", diff --git a/frontend/src/components/CommunicationArea.vue b/frontend/src/components/CommunicationArea.vue index 2bfb77ab..d262a3de 100644 --- a/frontend/src/components/CommunicationArea.vue +++ b/frontend/src/components/CommunicationArea.vue @@ -4,7 +4,9 @@