diff --git a/crm/api/doc.py b/crm/api/doc.py
index 8fc1f705..199c99b1 100644
--- a/crm/api/doc.py
+++ b/crm/api/doc.py
@@ -240,7 +240,8 @@ def get_list_data(
"views": get_views(doctype),
"total_count": len(frappe.get_list(doctype, filters=filters)),
"row_count": len(data),
- "form_script": get_form_script(doctype)
+ "form_script": get_form_script(doctype),
+ "list_script": get_form_script(doctype, "List"),
}
diff --git a/crm/api/notifications.py b/crm/api/notifications.py
index bdbe9118..3dde662c 100644
--- a/crm/api/notifications.py
+++ b/crm/api/notifications.py
@@ -4,9 +4,6 @@ from frappe.query_builder import Order
@frappe.whitelist()
def get_notifications():
- if frappe.session.user == "Guest":
- frappe.throw("Authentication failed", exc=frappe.AuthenticationError)
-
Notification = frappe.qb.DocType("CRM Notification")
query = (
frappe.qb.from_(Notification)
@@ -46,9 +43,6 @@ def get_notifications():
@frappe.whitelist()
def mark_as_read(user=None, comment=None):
- if frappe.session.user == "Guest":
- frappe.throw("Authentication failed", exc=frappe.AuthenticationError)
-
user = user or frappe.session.user
filters = {"to_user": user, "read": False}
if comment:
diff --git a/crm/api/session.py b/crm/api/session.py
index c6218317..3902ff7f 100644
--- a/crm/api/session.py
+++ b/crm/api/session.py
@@ -1,11 +1,8 @@
import frappe
-@frappe.whitelist(allow_guest=True)
+@frappe.whitelist()
def get_users():
- if frappe.session.user == "Guest":
- frappe.throw("Authentication failed", exc=frappe.AuthenticationError)
-
users = frappe.qb.get_query(
"User",
fields=["name", "email", "enabled", "user_image", "full_name", "user_type"],
@@ -24,9 +21,6 @@ def get_users():
@frappe.whitelist()
def get_contacts():
- if frappe.session.user == "Guest":
- frappe.throw("Authentication failed", exc=frappe.AuthenticationError)
-
contacts = frappe.get_all(
"Contact",
fields=[
@@ -66,9 +60,6 @@ def get_contacts():
@frappe.whitelist()
def get_lead_contacts():
- if frappe.session.user == "Guest":
- frappe.throw("Authentication failed", exc=frappe.AuthenticationError)
-
lead_contacts = frappe.get_all(
"CRM Lead",
fields=[
@@ -88,9 +79,6 @@ def get_lead_contacts():
@frappe.whitelist()
def get_organizations():
- if frappe.session.user == "Guest":
- frappe.throw("Authentication failed", exc=frappe.AuthenticationError)
-
organizations = frappe.qb.get_query(
"CRM Organization",
fields=['*'],
diff --git a/crm/api/views.py b/crm/api/views.py
index 6a95adbf..f70246e1 100644
--- a/crm/api/views.py
+++ b/crm/api/views.py
@@ -4,9 +4,6 @@ from pypika import Criterion
@frappe.whitelist()
def get_views(doctype):
- if frappe.session.user == "Guest":
- frappe.throw("Authentication failed", exc=frappe.AuthenticationError)
-
View = frappe.qb.DocType("CRM View Settings")
query = (
frappe.qb.from_(View)
diff --git a/crm/fcrm/doctype/crm_call_log/crm_call_log.py b/crm/fcrm/doctype/crm_call_log/crm_call_log.py
index 6c646e4c..0147b9ac 100644
--- a/crm/fcrm/doctype/crm_call_log/crm_call_log.py
+++ b/crm/fcrm/doctype/crm_call_log/crm_call_log.py
@@ -93,7 +93,7 @@ def get_call_log(name):
if c:
return [c.full_name, c.image]
return [None, None]
-
+
def get_lead_contact(number):
l = frappe.db.get_value("CRM Lead", {"mobile_no": number, "converted": 0}, ["lead_name", "image"], as_dict=True)
if l:
diff --git a/crm/fcrm/doctype/crm_form_script/crm_form_script.js b/crm/fcrm/doctype/crm_form_script/crm_form_script.js
index 7f6f150e..9df643d5 100644
--- a/crm/fcrm/doctype/crm_form_script/crm_form_script.js
+++ b/crm/fcrm/doctype/crm_form_script/crm_form_script.js
@@ -1,8 +1,38 @@
// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-// frappe.ui.form.on("CRM Form Script", {
-// refresh(frm) {
+frappe.ui.form.on("CRM Form Script", {
+ refresh(frm) {
+ frm.set_query("dt", {
+ filters: {
+ istable: 0,
+ },
+ });
+ },
+ view(frm) {
+ let has_form_boilerplate = frm.doc.script.includes(
+ "function setupForm("
+ );
+ let has_list_boilerplate = frm.doc.script.includes(
+ "function setupList("
+ );
-// },
-// });
+ if (frm.doc.view == "Form" && !has_form_boilerplate) {
+ frm.doc.script = `
+function setupForm({ doc }) {
+ return {
+ actions: [],
+ }
+}`.trim();
+ }
+ if (frm.doc.view == "List" && !has_list_boilerplate) {
+ frm.doc.script = `
+function setupList({ list }) {
+ return {
+ actions: [],
+ bulk_actions: [],
+ }
+}`.trim();
+ }
+ },
+});
diff --git a/crm/fcrm/doctype/crm_form_script/crm_form_script.json b/crm/fcrm/doctype/crm_form_script/crm_form_script.json
index b883e804..9a026098 100644
--- a/crm/fcrm/doctype/crm_form_script/crm_form_script.json
+++ b/crm/fcrm/doctype/crm_form_script/crm_form_script.json
@@ -7,6 +7,7 @@
"engine": "InnoDB",
"field_order": [
"dt",
+ "view",
"column_break_gboh",
"enabled",
"section_break_xeox",
@@ -36,16 +37,26 @@
"label": "Enabled"
},
{
- "default": "function setupForm({ doc }) {\n return {\n actions: []\n }\n}",
+ "default": "function setupForm({ doc }) {\n return {\n actions: [],\n }\n}",
+ "documentation_url": "https://docs.frappe.io/crm/custom-actions",
"fieldname": "script",
"fieldtype": "Code",
"label": "Script",
"options": "JS"
+ },
+ {
+ "default": "Form",
+ "fieldname": "view",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Apply To",
+ "options": "Form\nList",
+ "set_only_once": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2024-01-19 21:52:46.078626",
+ "modified": "2024-04-10 18:27:17.617602",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Form Script",
diff --git a/crm/fcrm/doctype/crm_form_script/crm_form_script.py b/crm/fcrm/doctype/crm_form_script/crm_form_script.py
index 32649d62..ff93ff4f 100644
--- a/crm/fcrm/doctype/crm_form_script/crm_form_script.py
+++ b/crm/fcrm/doctype/crm_form_script/crm_form_script.py
@@ -14,6 +14,7 @@ class CRMFormScript(Document):
if self.dt and self.enabled:
filters = {
"dt": self.dt,
+ "view": self.view,
"enabled": 1,
}
if self.name:
@@ -27,13 +28,14 @@ class CRMFormScript(Document):
frappe.DuplicateEntryError,
)
-def get_form_script(dt):
- """Returns the script for the given doctype"""
+def get_form_script(dt, view="Form"):
+ """Returns the form script for the given doctype"""
FormScript = frappe.qb.DocType("CRM Form Script")
query = (
frappe.qb.from_(FormScript)
.select("script")
.where(FormScript.dt == dt)
+ .where(FormScript.view == view)
.where(FormScript.enabled == 1)
.limit(1)
)
diff --git a/frontend/src/components/Filter.vue b/frontend/src/components/Filter.vue
index be0dc765..76dbeabe 100644
--- a/frontend/src/components/Filter.vue
+++ b/frontend/src/components/Filter.vue
@@ -327,7 +327,7 @@ function getValSelect(f) {
if (fieldtype == 'Dynamic Link') {
return h(FormControl, { type: 'text' })
}
- return h(Link, { class: 'form-control', doctype: options })
+ return h(Link, { class: 'form-control', doctype: options, value: f.value })
} else if (typeNumber.includes(fieldtype)) {
return h(FormControl, { type: 'number' })
} else if (typeDate.includes(fieldtype) && operator == 'between') {
@@ -437,8 +437,6 @@ function updateOperator(event, filter) {
function isSameTypeOperator(oldOperator, newOperator) {
let textOperators = [
- 'like',
- 'not like',
'equals',
'not equals',
'in',
diff --git a/frontend/src/components/ListViews/CallLogsListView.vue b/frontend/src/components/ListViews/CallLogsListView.vue
index 5d2cbe80..45c34b74 100644
--- a/frontend/src/components/ListViews/CallLogsListView.vue
+++ b/frontend/src/components/ListViews/CallLogsListView.vue
@@ -103,7 +103,7 @@ import {
Dropdown,
call,
} from 'frappe-ui'
-import { setupBulkActions, createToast } from '@/utils'
+import { setupListActions, createToast } from '@/utils'
import { globalStore } from '@/stores/global'
import { onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
@@ -181,6 +181,7 @@ function deleteValues(selections, unselectAll) {
}
const customBulkActions = ref([])
+const customListActions = ref([])
function bulkActions(selections, unselectAll) {
let actions = [
@@ -209,7 +210,18 @@ function bulkActions(selections, unselectAll) {
onMounted(() => {
if (!list.value?.data) return
- setupBulkActions(list.value.data)
+ setupListActions(list.value.data, {
+ list: list.value,
+ call,
+ createToast,
+ $dialog,
+ router,
+ })
customBulkActions.value = list.value?.data?.bulkActions || []
+ customListActions.value = list.value?.data?.listActions || []
+})
+
+defineExpose({
+ customListActions,
})
diff --git a/frontend/src/components/ListViews/ContactsListView.vue b/frontend/src/components/ListViews/ContactsListView.vue
index 5a9781d7..64fc550b 100644
--- a/frontend/src/components/ListViews/ContactsListView.vue
+++ b/frontend/src/components/ListViews/ContactsListView.vue
@@ -103,7 +103,7 @@
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
import EditValueModal from '@/components/Modals/EditValueModal.vue'
import { globalStore } from '@/stores/global'
-import { createToast } from '@/utils'
+import { setupListActions, createToast } from '@/utils'
import {
Avatar,
ListView,
@@ -117,7 +117,8 @@ import {
Dropdown,
call,
} from 'frappe-ui'
-import { ref, watch } from 'vue'
+import { ref, watch, onMounted } from 'vue'
+import { useRouter } from 'vue-router'
const props = defineProps({
rows: {
@@ -150,6 +151,8 @@ const emit = defineEmits([
const pageLengthCount = defineModel()
const list = defineModel('list')
+const router = useRouter()
+
const { $dialog } = globalStore()
watch(pageLengthCount, (val, old_value) => {
@@ -199,6 +202,8 @@ function deleteValues(selections, unselectAll) {
})
}
+const customListActions = ref([])
+
function bulkActions(selections, unselectAll) {
let actions = [
{
@@ -212,4 +217,21 @@ function bulkActions(selections, unselectAll) {
]
return actions
}
+
+onMounted(() => {
+ if (!list.value?.data) return
+ setupListActions(list.value.data, {
+ list: list.value,
+ call,
+ createToast,
+ $dialog,
+ router,
+ })
+ // customBulkActions.value = list.value?.data?.bulkActions || []
+ customListActions.value = list.value?.data?.listActions || []
+})
+
+defineExpose({
+ customListActions,
+})
diff --git a/frontend/src/components/ListViews/DealsListView.vue b/frontend/src/components/ListViews/DealsListView.vue
index e4988649..57a93e57 100644
--- a/frontend/src/components/ListViews/DealsListView.vue
+++ b/frontend/src/components/ListViews/DealsListView.vue
@@ -146,7 +146,7 @@ import {
call,
Tooltip,
} from 'frappe-ui'
-import { setupBulkActions, createToast } from '@/utils'
+import { setupListActions, createToast } from '@/utils'
import { globalStore } from '@/stores/global'
import { onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
@@ -234,6 +234,7 @@ function deleteValues(selections, unselectAll) {
}
const customBulkActions = ref([])
+const customListActions = ref([])
function bulkActions(selections, unselectAll) {
let actions = [
@@ -266,7 +267,18 @@ function bulkActions(selections, unselectAll) {
onMounted(() => {
if (!list.value?.data) return
- setupBulkActions(list.value.data)
+ setupListActions(list.value.data, {
+ list: list.value,
+ call,
+ createToast,
+ $dialog,
+ router,
+ })
customBulkActions.value = list.value?.data?.bulkActions || []
+ customListActions.value = list.value?.data?.listActions || []
+})
+
+defineExpose({
+ customListActions,
})
diff --git a/frontend/src/components/ListViews/EmailTemplatesListView.vue b/frontend/src/components/ListViews/EmailTemplatesListView.vue
index 34afca15..b260d0e3 100644
--- a/frontend/src/components/ListViews/EmailTemplatesListView.vue
+++ b/frontend/src/components/ListViews/EmailTemplatesListView.vue
@@ -85,7 +85,7 @@
diff --git a/frontend/src/components/ListViews/LeadsListView.vue b/frontend/src/components/ListViews/LeadsListView.vue
index 1483b574..a78a62ec 100644
--- a/frontend/src/components/ListViews/LeadsListView.vue
+++ b/frontend/src/components/ListViews/LeadsListView.vue
@@ -155,7 +155,7 @@ import {
call,
Tooltip,
} from 'frappe-ui'
-import { setupBulkActions, createToast } from '@/utils'
+import { setupListActions, createToast } from '@/utils'
import { globalStore } from '@/stores/global'
import { onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
@@ -243,6 +243,7 @@ function deleteValues(selections, unselectAll) {
}
const customBulkActions = ref([])
+const customListActions = ref([])
function bulkActions(selections, unselectAll) {
let actions = [
@@ -275,7 +276,18 @@ function bulkActions(selections, unselectAll) {
onMounted(() => {
if (!list.value?.data) return
- setupBulkActions(list.value.data)
+ setupListActions(list.value.data, {
+ list: list.value,
+ call,
+ createToast,
+ $dialog,
+ router,
+ })
customBulkActions.value = list.value?.data?.bulkActions || []
+ customListActions.value = list.value?.data?.listActions || []
+})
+
+defineExpose({
+ customListActions,
})
diff --git a/frontend/src/components/ListViews/OrganizationsListView.vue b/frontend/src/components/ListViews/OrganizationsListView.vue
index cd8d677d..059f661b 100644
--- a/frontend/src/components/ListViews/OrganizationsListView.vue
+++ b/frontend/src/components/ListViews/OrganizationsListView.vue
@@ -88,7 +88,7 @@
diff --git a/frontend/src/components/ListViews/TasksListView.vue b/frontend/src/components/ListViews/TasksListView.vue
index ab6b21a1..33898cf3 100644
--- a/frontend/src/components/ListViews/TasksListView.vue
+++ b/frontend/src/components/ListViews/TasksListView.vue
@@ -106,7 +106,7 @@ import CalendarIcon from '@/components/Icons/CalendarIcon.vue'
import EditValueModal from '@/components/Modals/EditValueModal.vue'
import { dateFormat } from '@/utils'
import { globalStore } from '@/stores/global'
-import { createToast } from '@/utils'
+import { setupListActions, createToast } from '@/utils'
import {
Avatar,
ListView,
@@ -120,7 +120,8 @@ import {
call,
Tooltip,
} from 'frappe-ui'
-import { ref, watch } from 'vue'
+import { ref, watch, onMounted } from 'vue'
+import { useRouter } from 'vue-router'
const props = defineProps({
rows: {
@@ -154,6 +155,8 @@ const emit = defineEmits([
const pageLengthCount = defineModel()
const list = defineModel('list')
+const router = useRouter()
+
const { $dialog } = globalStore()
watch(pageLengthCount, (val, old_value) => {
@@ -203,6 +206,8 @@ function deleteValues(selections, unselectAll) {
})
}
+const customListActions = ref([])
+
function bulkActions(selections, unselectAll) {
let actions = [
{
@@ -216,4 +221,21 @@ function bulkActions(selections, unselectAll) {
]
return actions
}
+
+onMounted(() => {
+ if (!list.value?.data) return
+ setupListActions(list.value.data, {
+ list: list.value,
+ call,
+ createToast,
+ $dialog,
+ router,
+ })
+ // customBulkActions.value = list.value?.data?.bulkActions || []
+ customListActions.value = list.value?.data?.listActions || []
+})
+
+defineExpose({
+ customListActions,
+})
diff --git a/frontend/src/pages/CallLogs.vue b/frontend/src/pages/CallLogs.vue
index 1c6b4ace..7d200827 100644
--- a/frontend/src/pages/CallLogs.vue
+++ b/frontend/src/pages/CallLogs.vue
@@ -3,6 +3,12 @@
+
+
+