Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(custom_field): fetch custom link options using server scripts #1381

Merged
merged 9 commits into from
Jul 29, 2023
45 changes: 42 additions & 3 deletions desk/src/pages/portal/TicketNew.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,23 @@
/>
<div class="grid grid-cols-3 gap-4">
<div
v-for="field in template.doc?.fields"
v-for="field in visibleCustomFields"
:key="field.label"
class="space-y-2"
>
<div class="text-xs">{{ field.label }}</div>
<div v-if="field.fieldtype === 'Link'">
<div
v-if="
field.fieldtype === 'Link' &&
field.fetch_options_from == 'DocType'
"
>
<SearchComplete
:doctype="field.doc_type"
@change="(v) => (customFields[field.fieldname] = v.value)"
/>
</div>
<div v-else-if="field.fieldtype === 'Link' && field.options">
<SearchComplete
:doctype="field.options"
@change="(v) => (customFields[field.fieldname] = v.value)"
Expand All @@ -33,6 +44,14 @@
@change="(v) => (customFields[field.fieldname] = v.value)"
/>
</div>
<div v-else-if="field.fetch_options_from === 'API'">
<Autocomplete
placeholder="Select an option"
:options="serverScriptOptions[field.fieldname]"
:value="customFields[field.fieldname]"
@change="(v) => (customFields[field.fieldname] = v.value)"
/>
</div>
</div>
</div>
<div
Expand Down Expand Up @@ -94,6 +113,7 @@ import {
Autocomplete,
Button,
Input,
call,
} from "frappe-ui";
import sanitizeHtml from "sanitize-html";
import { isEmpty } from "lodash";
Expand Down Expand Up @@ -131,6 +151,7 @@ const template = createDocumentResource({
name: props.templateId,
fields: ["about", "fields"],
auto: true,
onSuccess: fetchOptionsFromServerScript,
});

const articles = createListResource({
Expand All @@ -140,10 +161,13 @@ const articles = createListResource({
debounce: 500,
});

const visibleCustomFields = computed(() =>
template.doc?.fields?.filter((f) => !f.hide_from_customer)
);
const r = createResource({
url: "helpdesk.api.ticket.create_new",
validate(params) {
for (const field of template.doc?.fields || []) {
for (const field of visibleCustomFields.value || []) {
if (field.reqd && isEmpty(params.values[field.fieldname])) {
return `${field.label} is required`;
}
Expand Down Expand Up @@ -229,6 +253,21 @@ function searchArticles(term: string) {
articles.reload();
}

const serverScriptOptions = reactive({});
function fetchOptionsFromServerScript() {
visibleCustomFields.value.forEach((field) => {
if (field.fetch_options_from === "API") {
call(field.api_method).then((data) => {
const options = data.map((o) => ({
label: o,
value: o,
}));
serverScriptOptions[field.fieldname] = options;
});
}
});
}

onMounted(() => configStore.setTitle("New ticket"));
onUnmounted(() => configStore.setTitle());
</script>
88 changes: 46 additions & 42 deletions helpdesk/api/ticket.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,15 @@
ticket_doc.ticket_type = values.get("ticket_type")

if "contact" in values:
contact_doc = frappe.get_doc("Contact", values["contact"])
email_id = ""
if contact_doc.email_id:
email_id = contact_doc.email_id
elif contact_doc.email_ids and len(contact_doc.email_ids) > 0:
email_id = contact_doc.email_ids[0].email_id

ticket_doc.raised_by = email_id
ticket_doc.contact = contact_doc.name
contact_name = values["contact"]
ticket_doc.raised_by = get_contact_email(contact_name)
ticket_doc.contact = contact_name

if via_customer_portal:
if not frappe.db.exists(
{"doctype": "Contact", "email_id": frappe.session.user}
):
user_doc = frappe.get_doc("User", frappe.session.user)
new_contact_doc = frappe.get_doc(
doctype="Contact",
email_id=user_doc.email,
full_name=user_doc.full_name,
first_name=user_doc.first_name,
last_name=user_doc.last_name,
user=user_doc.name,
)
new_contact_doc.append(
"email_ids", {"email_id": user_doc.email, "is_primary": True}
)
new_contact_doc.insert(ignore_permissions=True)
ticket_doc.contact = new_contact_doc.name
if not frappe.db.exists("Contact", {"email_id": frappe.session.user}):
new_contact_name = create_contact_from_user(frappe.session.user)
ticket_doc.raised_by = frappe.session.user
ticket_doc.contact = new_contact_name

ticket_doc.subject = values["subject"]
ticket_doc.description = values["description"]
Expand All @@ -52,23 +33,22 @@
for field in template_fields:
if field.fieldname in ["subject", "description"]:
continue
if field.auto_set and field.auto_set_via == "Backend (Python)":
if not field.reqd and field.fieldname not in values:
continue
else:
if field.fieldname not in values:
continue
ticket_doc.append(
"custom_fields",
{
"label": field.label,
"fieldname": field.fieldname,
"value": values[field.fieldname],
"route": f"/app/{cleanup_page_name(field.options)}/{values[field.fieldname]}"
if field.fieldtype == "Link"
else "",
"is_action_field": field.is_action_field,
},
)
if field.reqd and field.fieldname not in values:
frappe.throw(f"Field {field.label} is required")
ticket_doc.append(
"custom_fields",
{
"label": field.label,
"fieldname": field.fieldname,
"value": values[field.fieldname],
"hide_from_customer": field.hide_from_customer,
"route": f"/app/{cleanup_page_name(field.options)}/{values[field.fieldname]}"
if field.fieldtype == "Link"
else "",
},
)

ticket_doc.insert(ignore_permissions=True)
# TODO: remove this if condition after refactoring doctype/ticket.py logic regarding this
Expand All @@ -80,6 +60,30 @@
return ticket_doc


def get_contact_email(contact_name):
email_id = frappe.db.get_value("Contact", contact_name, "email_id")
if email_id:
return email_id
email_id = frappe.db.get_value("Contact Email", {"parent": contact_name}, "email_id")

Check failure on line 67 in helpdesk/api/ticket.py

View workflow job for this annotation

GitHub Actions / Black - Reviewdog

[black-format] reported by reviewdog 🐶 Raw Output: helpdesk/api/ticket.py:67:- email_id = frappe.db.get_value("Contact Email", {"parent": contact_name}, "email_id") helpdesk/api/ticket.py:67:+ email_id = frappe.db.get_value( helpdesk/api/ticket.py:68:+ "Contact Email", {"parent": contact_name}, "email_id" helpdesk/api/ticket.py:69:+ )
if email_id:
return email_id

Check failure on line 70 in helpdesk/api/ticket.py

View workflow job for this annotation

GitHub Actions / Black - Reviewdog

[black-format] reported by reviewdog 🐶 Raw Output: helpdesk/api/ticket.py:72:+
def create_contact_from_user(user):
user_doc = frappe.get_doc("User", user)
new_contact_doc = frappe.get_doc(
doctype="Contact",
email_id=user_doc.email,
full_name=user_doc.full_name,
first_name=user_doc.first_name,
last_name=user_doc.last_name,
user=user_doc.name,
)
new_contact_doc.append(
"email_ids", {"email_id": user_doc.email, "is_primary": True}
)
new_contact_doc.insert(ignore_permissions=True)
return new_contact_doc.name

Check failure on line 86 in helpdesk/api/ticket.py

View workflow job for this annotation

GitHub Actions / Black - Reviewdog

[black-format] reported by reviewdog 🐶 Raw Output: helpdesk/api/ticket.py:89:+
def assign_ticket_to_agent(ticket_id, agent_id=None):
if not ticket_id:
return
Expand Down
4 changes: 2 additions & 2 deletions helpdesk/helpdesk/doctype/hd_team/hd_team.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def after_rename(self, olddn, newdn, merge=False):
# Update the condition for the linked assignment rule
rule = self.get_assignment_rule()
rule_doc = frappe.get_doc("Assignment Rule", rule)
rule_doc.assign_condition = f"status == 'Open' and hd_team == '{newdn}'"
rule_doc.assign_condition = f"status == 'Open' and agent_group == '{newdn}'"
rule_doc.save(ignore_permissions=True)

def on_trash(self):
Expand All @@ -43,7 +43,7 @@ def create_assignment_rule(self):
"Assignment Rule", f"{self.name} - Support Rotation"
)
rule_doc.document_type = "HD Ticket"
rule_doc.assign_condition = f"status == 'Open' and hd_team == '{self.name}'"
rule_doc.assign_condition = f"status == 'Open' and agent_group == '{self.name}'"
rule_doc.priority = 1
rule_doc.disabled = True # Disable the rule by default, when agents are added to the group, the rule will be enabled

Expand Down
10 changes: 9 additions & 1 deletion helpdesk/helpdesk/doctype/hd_ticket/hd_ticket.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,19 @@
publish_event("helpdesk:ticket-assignee-update", {"name": self.name})

def get_assigned_agent(self):
if self._assign:
# for some reason _assign is not set, maybe a framework bug?
if hasattr(self, "_assign") and self._assign:
assignees = json.loads(self._assign)
if len(assignees) > 0:
agent_doc = frappe.get_doc("HD Agent", assignees[0])
return agent_doc

from frappe.desk.form.assign_to import get
assignees = get({"doctype": "HD Ticket", "name": self.name})

Check failure on line 365 in helpdesk/helpdesk/doctype/hd_ticket/hd_ticket.py

View workflow job for this annotation

GitHub Actions / Black - Reviewdog

[black-format] reported by reviewdog 🐶 Raw Output: helpdesk/helpdesk/doctype/hd_ticket/hd_ticket.py:365:+
if len(assignees) > 0:
agent_doc = frappe.get_doc("HD Agent", assignees[0].owner)
return agent_doc

return None

def on_trash(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"fieldname",
"value",
"route",
"is_action_field"
"hide_from_customer"
],
"fields": [
{
Expand All @@ -38,15 +38,15 @@
},
{
"default": "0",
"fieldname": "is_action_field",
"fieldname": "hide_from_customer",
"fieldtype": "Check",
"label": "Is Action Field"
"label": "Hide from Customer"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2022-11-23 00:32:56.111155",
"modified": "2023-07-29 13:02:53.237459",
"modified_by": "Administrator",
"module": "Helpdesk",
"name": "HD Ticket Custom Field",
Expand All @@ -55,4 +55,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}
}
Empty file.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Empty file.
Loading
Loading