diff --git a/.eslintrc b/.eslintrc
index cdd6be1c0b..3711a7dbe6 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -140,6 +140,7 @@
"expect": true,
"context": true,
"before": true,
- "beforeEach": true
+ "beforeEach": true,
+ "qz": true
}
}
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 30ca6761a2..0000000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,29 +0,0 @@
-include MANIFEST.in
-include requirements.txt
-include *.json
-include *.md
-include *.py
-recursive-include frappe *.css
-recursive-include frappe *.dat
-recursive-include frappe *.eot
-recursive-include frappe *.gif
-recursive-include frappe *.html
-recursive-include frappe *.jpg
-recursive-include frappe *.js
-recursive-include frappe *.json
-recursive-include frappe *.md
-recursive-include frappe *.otf
-recursive-include frappe *.png
-recursive-include frappe *.py
-recursive-include frappe *.sql
-recursive-include frappe *.svg
-recursive-include frappe *.swf
-recursive-include frappe *.ttf
-recursive-include frappe *.woff
-recursive-include frappe *.xml
-recursive-include frappe *.csv
-recursive-include frappe *.ico
-recursive-include frappe *.less
-recursive-include frappe *.txt
-recursive-include frappe/public *
-recursive-exclude * *.pyc
diff --git a/cypress/integration/file_uploader.js b/cypress/integration/file_uploader.js
new file mode 100644
index 0000000000..b58e0d49a8
--- /dev/null
+++ b/cypress/integration/file_uploader.js
@@ -0,0 +1,61 @@
+context('FileUploader', () => {
+ before(() => {
+ cy.login('Administrator', 'qwe');
+ cy.visit('/desk');
+ });
+
+ function open_upload_dialog() {
+ cy.window().its('frappe').then(frappe => {
+ new frappe.ui.FileUploader();
+ });
+ }
+
+ it('upload dialog api works', () => {
+ open_upload_dialog();
+ cy.get_open_dialog().should('contain', 'Drag and drop files');
+ cy.hide_dialog();
+ });
+
+ it('should accept dropped files', () => {
+ open_upload_dialog();
+
+ cy.fixture('example.json').then(fileContent => {
+ cy.get_open_dialog().find('.file-upload-area').upload(
+ { fileContent, fileName: 'example.json', mimeType: 'application/json' },
+ { subjectType: 'drag-n-drop' },
+ );
+ cy.get_open_dialog().find('.file-info').should('contain', 'example.json');
+ cy.server();
+ cy.route('POST', '/api/method/upload_file').as('upload_file');
+ cy.get_open_dialog().find('.btn-primary').click();
+ cy.wait('@upload_file').its('status').should('be', 200);
+ cy.get('.modal:visible').should('not.exist');
+ });
+ });
+
+ it('should accept uploaded files', () => {
+ open_upload_dialog();
+
+ cy.get_open_dialog().find('a:contains("uploaded file")').click();
+ cy.get_open_dialog().find('.tree-label:contains("example.json")').first().click();
+ cy.server();
+ cy.route('POST', '/api/method/upload_file').as('upload_file');
+ cy.get_open_dialog().find('.btn-primary').click();
+ cy.wait('@upload_file').its('response.body.message')
+ .should('have.property', 'file_url', '/private/files/example.json');
+ cy.get('.modal:visible').should('not.exist');
+ });
+
+ it('should accept web links', () => {
+ open_upload_dialog();
+
+ cy.get_open_dialog().find('a:contains("web link")').click();
+ cy.get_open_dialog().find('.file-web-link input').type('https://github.com');
+ cy.server();
+ cy.route('POST', '/api/method/upload_file').as('upload_file');
+ cy.get_open_dialog().find('.btn-primary').click();
+ cy.wait('@upload_file').its('response.body.message')
+ .should('have.property', 'file_url', 'https://github.com');
+ cy.get('.modal:visible').should('not.exist');
+ });
+});
diff --git a/cypress/integration/table_multiselect.js b/cypress/integration/table_multiselect.js
index e53584640b..cca9a6eb46 100644
--- a/cypress/integration/table_multiselect.js
+++ b/cypress/integration/table_multiselect.js
@@ -9,7 +9,7 @@ context('Table MultiSelect', () => {
cy.new_form('Assignment Rule');
cy.fill_field('__newname', name);
cy.fill_field('document_type', 'ToDo');
- cy.fill_field('assign_condition', 'status=="Open"');
+ cy.fill_field('assign_condition', 'status=="Open"', 'Code');
cy.get('input[data-fieldname="users"]').focus().as('input');
cy.get('input[data-fieldname="users"] + ul').should('be.visible');
cy.get('@input').type('test{enter}', { delay: 100 });
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index 8c2156e9f4..23bbc8af24 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -1,3 +1,4 @@
+import 'cypress-file-upload';
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
@@ -38,7 +39,10 @@ Cypress.Commands.add('fill_field', (fieldname, value, fieldtype='Data') => {
let selector = `.form-control[data-fieldname="${fieldname}"]`;
if (fieldtype === 'Text Editor') {
- selector = `[data-fieldname="${fieldname}"] .ql-editor`;
+ selector = `[data-fieldname="${fieldname}"] .ql-editor[contenteditable=true]`;
+ }
+ if (fieldtype === 'Code') {
+ selector = `[data-fieldname="${fieldname}"] .ace_text-input`;
}
cy.get(selector).as('input');
@@ -46,7 +50,7 @@ Cypress.Commands.add('fill_field', (fieldname, value, fieldtype='Data') => {
if (fieldtype === 'Select') {
return cy.get('@input').select(value);
} else {
- return cy.get('@input').type(value);
+ return cy.get('@input').type(value, {waitForAnimations: false});
}
});
@@ -75,3 +79,12 @@ Cypress.Commands.add('dialog', (title, fields) => {
return d;
});
});
+
+Cypress.Commands.add('get_open_dialog', () => {
+ return cy.get('.modal:visible').last();
+});
+
+Cypress.Commands.add('hide_dialog', () => {
+ cy.get_open_dialog().find('.btn-modal-close').click();
+ cy.get('.modal:visible').should('not.exist');
+});
diff --git a/frappe/__init__.py b/frappe/__init__.py
index c80f60ac3d..cd662cd6cb 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -16,7 +16,6 @@ from faker import Faker
# public
from .exceptions import *
from .utils.jinja import (get_jenv, get_template, render_template, get_email_from_template, get_jloader)
-from .utils.error import get_frame_locals
# Hamless for Python 3
# For Python 2 set default encoding to utf-8
@@ -188,15 +187,20 @@ def connect(site=None, db_name=None):
local.db = get_db(user=db_name or local.conf.db_name)
set_user("Administrator")
-def connect_read_only():
+def connect_replica():
from frappe.database import get_db
+ user = local.conf.db_name
+ password = local.conf.db_password
- local.read_only_db = get_db(local.conf.slave_host, local.conf.slave_db_name,
- local.conf.slave_db_password)
+ if local.conf.different_credentials_for_replica:
+ user = local.conf.replica_db_name
+ password = local.conf.replica_db_password
+
+ local.replica_db = get_db(host=local.conf.replica_host, user=user, password=password)
# swap db connections
- local.master_db = local.db
- local.db = local.read_only_db
+ local.primary_db = local.db
+ local.db = local.replica_db
def get_site_config(sites_path=None, site_path=None):
"""Returns `site_config.json` combined with `sites/common_site_config.json`.
@@ -274,7 +278,7 @@ def errprint(msg):
if not request or (not "cmd" in local.form_dict) or conf.developer_mode:
print(msg)
- error_log.append({"exc": msg, "locals": get_frame_locals()})
+ error_log.append({"exc": msg})
def log(msg):
"""Add to `debug_log`.
@@ -496,16 +500,17 @@ def whitelist(allow_guest=False, xss_safe=False):
def read_only():
def innfn(fn):
def wrapper_fn(*args, **kwargs):
- if conf.use_slave_for_read_only:
- connect_read_only()
+ if conf.read_from_replica:
+ connect_replica()
+
try:
retval = fn(*args, **get_newargs(fn, kwargs))
except:
raise
finally:
- if local and hasattr(local, 'master_db'):
+ if local and hasattr(local, 'primary_db'):
local.db.close()
- local.db = local.master_db
+ local.db = local.primary_db
return retval
return wrapper_fn
@@ -1262,7 +1267,7 @@ def get_all(doctype, *args, **kwargs):
:param fields: List of fields or `*`. Default is: `["name"]`.
:param filters: List of filters (see example).
:param order_by: Order By e.g. `modified desc`.
- :param limit_page_start: Start results at record #. Default 0.
+ :param limit_start: Start results at record #. Default 0.
:param limit_page_length: No of records in the page. Default 20.
Example usage:
@@ -1297,7 +1302,7 @@ def get_value(*args, **kwargs):
def as_json(obj, indent=1):
from frappe.utils.response import json_handler
- return json.dumps(obj, indent=indent, sort_keys=True, default=json_handler)
+ return json.dumps(obj, indent=indent, sort_keys=True, default=json_handler, separators=(',', ': '))
def are_emails_muted():
from frappe.utils import cint
@@ -1329,14 +1334,15 @@ def format(*args, **kwargs):
import frappe.utils.formatters
return frappe.utils.formatters.format_value(*args, **kwargs)
-def get_print(doctype=None, name=None, print_format=None, style=None, html=None, as_pdf=False, doc=None, output = None, no_letterhead = 0):
+def get_print(doctype=None, name=None, print_format=None, style=None, html=None, as_pdf=False, doc=None, output = None, no_letterhead = 0, password=None):
"""Get Print Format for given document.
:param doctype: DocType of document.
:param name: Name of document.
:param print_format: Print Format name. Default 'Standard',
:param style: Print Format style.
- :param as_pdf: Return as PDF. Default False."""
+ :param as_pdf: Return as PDF. Default False.
+ :param password: Password to encrypt the pdf with. Default None"""
from frappe.website.render import build_page
from frappe.utils.pdf import get_pdf
@@ -1347,15 +1353,19 @@ def get_print(doctype=None, name=None, print_format=None, style=None, html=None,
local.form_dict.doc = doc
local.form_dict.no_letterhead = no_letterhead
+ options = None
+ if password:
+ options = {'password': password}
+
if not html:
html = build_page("printview")
if as_pdf:
- return get_pdf(html, output = output)
+ return get_pdf(html, output = output, options = options)
else:
return html
-def attach_print(doctype, name, file_name=None, print_format=None, style=None, html=None, doc=None, lang=None, print_letterhead=True):
+def attach_print(doctype, name, file_name=None, print_format=None, style=None, html=None, doc=None, lang=None, print_letterhead=True, password=None):
from frappe.utils import scrub_urls
if not file_name: file_name = name
@@ -1374,12 +1384,12 @@ def attach_print(doctype, name, file_name=None, print_format=None, style=None, h
if int(print_settings.send_print_as_pdf or 0):
out = {
"fname": file_name + ".pdf",
- "fcontent": get_print(doctype, name, print_format=print_format, style=style, html=html, as_pdf=True, doc=doc, no_letterhead=no_letterhead)
+ "fcontent": get_print(doctype, name, print_format=print_format, style=style, html=html, as_pdf=True, doc=doc, no_letterhead=no_letterhead, password=password)
}
else:
out = {
"fname": file_name + ".html",
- "fcontent": scrub_urls(get_print(doctype, name, print_format=print_format, style=style, html=html, doc=doc, no_letterhead=no_letterhead)).encode("utf-8")
+ "fcontent": scrub_urls(get_print(doctype, name, print_format=print_format, style=style, html=html, doc=doc, no_letterhead=no_letterhead, password=password)).encode("utf-8")
}
local.flags.ignore_print_permissions = False
diff --git a/frappe/automation/doctype/assignment_rule/assignment_rule.json b/frappe/automation/doctype/assignment_rule/assignment_rule.json
index 1996281acf..984ca9928a 100644
--- a/frappe/automation/doctype/assignment_rule/assignment_rule.json
+++ b/frappe/automation/doctype/assignment_rule/assignment_rule.json
@@ -22,6 +22,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "document_type",
"fieldtype": "Link",
"hidden": 0,
@@ -56,6 +57,7 @@
"collapsible": 0,
"columns": 0,
"description": "Higher priority rule will be applied first",
+ "fetch_if_empty": 0,
"fieldname": "priority",
"fieldtype": "Int",
"hidden": 0,
@@ -88,6 +90,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "disabled",
"fieldtype": "Check",
"hidden": 0,
@@ -120,6 +123,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
@@ -153,6 +157,7 @@
"columns": 0,
"default": "Automatic Assignment",
"description": "Example: {{ subject }}",
+ "fetch_if_empty": 0,
"fieldname": "description",
"fieldtype": "Small Text",
"hidden": 0,
@@ -185,6 +190,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "assignment_rules_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -218,8 +224,9 @@
"collapsible": 0,
"columns": 0,
"description": "Simple Python Expression, Example: status == 'Open' and type == 'Bug'",
+ "fetch_if_empty": 0,
"fieldname": "assign_condition",
- "fieldtype": "Small Text",
+ "fieldtype": "Code",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -250,6 +257,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_6",
"fieldtype": "Column Break",
"hidden": 0,
@@ -282,8 +290,9 @@
"collapsible": 0,
"columns": 0,
"description": "Simple Python Expression, Example: Status in (\"Closed\", \"Cancelled\")",
+ "fetch_if_empty": 0,
"fieldname": "unassign_condition",
- "fieldtype": "Small Text",
+ "fieldtype": "Code",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -314,6 +323,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "assign_to_users_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -346,6 +356,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "rule",
"fieldtype": "Select",
"hidden": 0,
@@ -379,6 +390,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "users",
"fieldtype": "Table MultiSelect",
"hidden": 0,
@@ -412,6 +424,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "last_user",
"fieldtype": "Link",
"hidden": 0,
@@ -440,16 +453,14 @@
}
],
"has_web_view": 0,
- "hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
- "image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-03-08 15:13:01.379471",
+ "modified": "2019-04-16 17:46:04.890120",
"modified_by": "Administrator",
"module": "Automation",
"name": "Assignment Rule",
@@ -478,7 +489,6 @@
],
"quick_entry": 0,
"read_only": 0,
- "read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
diff --git a/frappe/automation/doctype/assignment_rule/assignment_rule.py b/frappe/automation/doctype/assignment_rule/assignment_rule.py
index 6c6ad3b68a..d729e87437 100644
--- a/frappe/automation/doctype/assignment_rule/assignment_rule.py
+++ b/frappe/automation/doctype/assignment_rule/assignment_rule.py
@@ -7,13 +7,14 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe.desk.form import assign_to
+import frappe.cache_manager
class AssignmentRule(Document):
def on_update(self): # pylint: disable=no-self-use
- frappe.cache().delete_value('assignment_rule')
+ frappe.cache_manager.clear_doctype_map('Assignment Rule', self.name)
def after_rename(self): # pylint: disable=no-self-use
- frappe.cache().delete_value('assignment_rule')
+ frappe.cache_manager.clear_doctype_map('Assignment Rule', self.name)
def apply_unassign(self, doc, assignments):
if (self.unassign_condition and
@@ -113,14 +114,14 @@ def apply(doc, method):
if frappe.flags.in_patch or frappe.flags.in_install:
return
- assignment_rules = frappe.cache().get_value('assignment_rule', get_assignment_rules)
+ assignment_rules = frappe.cache_manager.get_doctype_map('Assignment Rule', doc.doctype, dict(
+ document_type = doc.doctype, disabled = 0), order_by = 'priority desc')
+
assignment_rule_docs = []
- # build rules
- if doc.doctype in assignment_rules:
- # multiple auto assigns
- for d in frappe.db.get_all('Assignment Rule', dict(document_type=doc.doctype, disabled = 0), order_by = 'priority desc'):
- assignment_rule_docs.append(frappe.get_doc('Assignment Rule', d.name))
+ # multiple auto assigns
+ for d in assignment_rules:
+ assignment_rule_docs.append(frappe.get_doc('Assignment Rule', d.name))
if not assignment_rule_docs:
return
diff --git a/frappe/core/doctype/feedback_request/__init__.py b/frappe/automation/doctype/milestone/__init__.py
similarity index 100%
rename from frappe/core/doctype/feedback_request/__init__.py
rename to frappe/automation/doctype/milestone/__init__.py
diff --git a/frappe/automation/doctype/milestone/milestone.js b/frappe/automation/doctype/milestone/milestone.js
new file mode 100644
index 0000000000..9a1cf577ff
--- /dev/null
+++ b/frappe/automation/doctype/milestone/milestone.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, Frappe Technologies and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Milestone', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/frappe/automation/doctype/milestone/milestone.json b/frappe/automation/doctype/milestone/milestone.json
new file mode 100644
index 0000000000..8360ce7bf4
--- /dev/null
+++ b/frappe/automation/doctype/milestone/milestone.json
@@ -0,0 +1,230 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "",
+ "beta": 0,
+ "creation": "2019-04-17 09:39:15.647817",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 0,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "reference_type",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Document Type",
+ "length": 0,
+ "no_copy": 0,
+ "options": "DocType",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 1,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "reference_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Document",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "track_field",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Track Field",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "value",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Value",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "milestone_tracker",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Milestone Tracker",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Milestone Tracker",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "in_create": 1,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2019-04-17 16:01:21.430344",
+ "modified_by": "Administrator",
+ "module": "Automation",
+ "name": "Milestone",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "title_field": "reference_type",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/frappe/automation/doctype/milestone/milestone.py b/frappe/automation/doctype/milestone/milestone.py
new file mode 100644
index 0000000000..64c073a378
--- /dev/null
+++ b/frappe/automation/doctype/milestone/milestone.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from frappe.model.document import Document
+
+class Milestone(Document):
+ pass
+
+def on_doctype_update():
+ frappe.db.add_index("Milestone", ["reference_type", "reference_name"])
diff --git a/frappe/automation/doctype/milestone/test_milestone.py b/frappe/automation/doctype/milestone/test_milestone.py
new file mode 100644
index 0000000000..75602d48db
--- /dev/null
+++ b/frappe/automation/doctype/milestone/test_milestone.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+#import frappe
+import unittest
+
+class TestMilestone(unittest.TestCase):
+ pass
diff --git a/frappe/core/doctype/feedback_trigger/__init__.py b/frappe/automation/doctype/milestone_tracker/__init__.py
similarity index 100%
rename from frappe/core/doctype/feedback_trigger/__init__.py
rename to frappe/automation/doctype/milestone_tracker/__init__.py
diff --git a/frappe/automation/doctype/milestone_tracker/milestone_tracker.js b/frappe/automation/doctype/milestone_tracker/milestone_tracker.js
new file mode 100644
index 0000000000..2a74bfb070
--- /dev/null
+++ b/frappe/automation/doctype/milestone_tracker/milestone_tracker.js
@@ -0,0 +1,33 @@
+// Copyright (c) 2019, Frappe Technologies and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Milestone Tracker', {
+ refresh: function(frm) {
+ frm.trigger('update_options');
+ },
+ document_type: function(frm) {
+ frm.trigger('update_options');
+ },
+ update_options: function(frm) {
+ // update select options for `track_field`
+ let doctype = frm.doc.document_type;
+ let track_fields = [];
+
+ if (doctype) {
+ frappe.model.with_doctype(doctype, () => {
+ // get all date and datetime fields
+ frappe.get_meta(doctype).fields.map(df => {
+ if (['Link', 'Select'].includes(df.fieldtype)) {
+ track_fields.push({label: df.label, value: df.fieldname});
+ }
+ });
+ frm.set_df_property('track_field', 'options', track_fields);
+ });
+ } else {
+ // update select options
+ frm.set_df_property('track_field', 'options', []);
+ }
+
+ },
+
+});
diff --git a/frappe/automation/doctype/milestone_tracker/milestone_tracker.json b/frappe/automation/doctype/milestone_tracker/milestone_tracker.json
new file mode 100644
index 0000000000..8e22e3e199
--- /dev/null
+++ b/frappe/automation/doctype/milestone_tracker/milestone_tracker.json
@@ -0,0 +1,162 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "format:{document_type}-{track_field}",
+ "beta": 0,
+ "creation": "2019-04-17 09:36:41.774774",
+ "custom": 0,
+ "description": "Track milestones for any document",
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 0,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "document_type",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Document Type to Track",
+ "length": 0,
+ "no_copy": 0,
+ "options": "DocType",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 1
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "track_field",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Field to Track",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Disabled",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2019-04-22 16:03:32.848937",
+ "modified_by": "Administrator",
+ "module": "Automation",
+ "name": "Milestone Tracker",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/frappe/automation/doctype/milestone_tracker/milestone_tracker.py b/frappe/automation/doctype/milestone_tracker/milestone_tracker.py
new file mode 100644
index 0000000000..baa1bcc075
--- /dev/null
+++ b/frappe/automation/doctype/milestone_tracker/milestone_tracker.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from frappe.model.document import Document
+import frappe.cache_manager
+
+class MilestoneTracker(Document):
+ def on_update(self):
+ frappe.cache_manager.clear_doctype_map('Milestone Tracker', self.name)
+
+ def on_trash(self):
+ frappe.cache_manager.clear_doctype_map('Milestone Tracker', self.name)
+
+ def apply(self, doc):
+ before_save = doc.get_doc_before_save()
+ from_value = before_save and before_save.get(self.track_field) or None
+ if from_value != doc.get(self.track_field):
+ frappe.get_doc(dict(
+ doctype = 'Milestone',
+ reference_type = doc.doctype,
+ reference_name = doc.name,
+ track_field = self.track_field,
+ from_value = from_value,
+ value = doc.get(self.track_field),
+ milestone_tracker = self.name,
+ )).insert(ignore_permissions=True)
+
+def evaluate_milestone(doc, event):
+ for d in frappe.cache_manager.get_doctype_map('Milestone Tracker', doc.doctype,
+ dict(document_type = doc.doctype, disabled=0)):
+ frappe.get_doc('Milestone Tracker', d.name).apply(doc)
diff --git a/frappe/automation/doctype/milestone_tracker/test_milestone_tracker.py b/frappe/automation/doctype/milestone_tracker/test_milestone_tracker.py
new file mode 100644
index 0000000000..c9bb6b7d5f
--- /dev/null
+++ b/frappe/automation/doctype/milestone_tracker/test_milestone_tracker.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestMilestoneTracker(unittest.TestCase):
+ def test_milestone(self):
+ frappe.db.sql('delete from `tabMilestone Tracker`')
+ frappe.get_doc(dict(
+ doctype = 'Milestone Tracker',
+ document_type = 'ToDo',
+ track_field = 'status'
+ )).insert()
+
+ todo = frappe.get_doc(dict(
+ doctype = 'ToDo',
+ description = 'test milestone'
+ )).insert()
+
+ milestones = frappe.get_all('Milestone',
+ fields = ['track_field', 'value', 'milestone_tracker'],
+ filters = dict(reference_type = todo.doctype, reference_name=todo.name))
+
+ self.assertEqual(len(milestones), 1)
+ self.assertEqual(milestones[0].track_field, 'status')
+ self.assertEqual(milestones[0].value, 'Open')
+
+ todo.status = 'Closed'
+ todo.save()
+
+ milestones = frappe.get_all('Milestone',
+ fields = ['track_field', 'value', 'milestone_tracker'],
+ filters = dict(reference_type = todo.doctype, reference_name=todo.name),
+ order_by = 'modified desc')
+
+ self.assertEqual(len(milestones), 2)
+ self.assertEqual(milestones[0].track_field, 'status')
+ self.assertEqual(milestones[0].value, 'Closed')
+
diff --git a/frappe/boot.py b/frappe/boot.py
index f166af91f7..4acb7ee3c1 100644
--- a/frappe/boot.py
+++ b/frappe/boot.py
@@ -16,8 +16,9 @@ from frappe.desk.form.load import get_meta_bundle
from frappe.utils.change_log import get_versions
from frappe.translate import get_lang_dict
from frappe.email.inbox import get_email_accounts
-from frappe.core.doctype.feedback_trigger.feedback_trigger import get_enabled_feedback_trigger
from frappe.social.doctype.energy_point_settings.energy_point_settings import is_energy_point_enabled
+from frappe.social.doctype.energy_point_log.energy_point_log import get_energy_points
+from frappe.social.doctype.post.post import frequently_visited_links
def get_bootinfo():
"""build and return boot info"""
@@ -75,11 +76,12 @@ def get_bootinfo():
bootinfo.calendars = sorted(frappe.get_hooks("calendars"))
bootinfo.treeviews = frappe.get_hooks("treeviews") or []
bootinfo.lang_dict = get_lang_dict()
- bootinfo.feedback_triggers = get_enabled_feedback_trigger()
bootinfo.gsuite_enabled = get_gsuite_status()
bootinfo.success_action = get_success_action()
bootinfo.update(get_email_accounts(user=frappe.session.user))
bootinfo.energy_points_enabled = is_energy_point_enabled()
+ bootinfo.points = get_energy_points(frappe.session.user)
+ bootinfo.frequently_visited_links = frequently_visited_links()
return bootinfo
diff --git a/frappe/cache_manager.py b/frappe/cache_manager.py
index a913f5fba9..6c9a59d375 100644
--- a/frappe/cache_manager.py
+++ b/frappe/cache_manager.py
@@ -3,31 +3,40 @@
from __future__ import unicode_literals
-import frappe
+import frappe, json
import frappe.defaults
from frappe.desk.notifications import (delete_notification_count_for,
clear_notifications)
common_default_keys = ["__default", "__global"]
-def clear_user_cache(user=None):
- cache = frappe.cache()
+global_cache_keys = ("app_hooks", "installed_apps",
+ "app_modules", "module_app", "notification_config", 'system_settings',
+ 'scheduler_events', 'time_zone', 'webhooks', 'active_domains',
+ 'active_modules', 'assignment_rule')
- groups = ("bootinfo", "user_recent", "roles", "user_doc", "lang",
+user_cache_keys = ("bootinfo", "user_recent", "roles", "user_doc", "lang",
"defaults", "user_permissions", "home_page", "linked_with",
"desktop_icons", 'portal_menu_items')
+doctype_cache_keys = ("meta", "form_meta", "table_columns", "last_modified",
+ "linked_doctypes", 'notifications', 'workflow' ,'energy_point_rule_map')
+
+
+def clear_user_cache(user=None):
+ cache = frappe.cache()
+
# this will automatically reload the global cache
# so it is important to clear this first
clear_notifications(user)
if user:
- for name in groups:
+ for name in user_cache_keys:
cache.hdel(name, user)
cache.delete_keys("user:" + user)
clear_defaults_cache(user)
else:
- for name in groups:
+ for name in user_cache_keys:
cache.delete_key(name)
clear_defaults_cache()
clear_global_cache()
@@ -37,10 +46,7 @@ def clear_global_cache():
clear_doctype_cache()
clear_website_cache()
- frappe.cache().delete_value(["app_hooks", "installed_apps",
- "app_modules", "module_app", "notification_config", 'system_settings',
- 'scheduler_events', 'time_zone', 'webhooks', 'active_domains',
- 'active_modules', 'assignment_rule'])
+ frappe.cache().delete_value(global_cache_keys)
frappe.setup_module_map()
def clear_defaults_cache(user=None):
@@ -63,11 +69,8 @@ def clear_doctype_cache(doctype=None):
for key in ('is_table', 'doctype_modules'):
cache.delete_value(key)
- groups = ["meta", "form_meta", "table_columns", "last_modified",
- "linked_doctypes", 'notifications', 'workflow']
-
def clear_single(dt):
- for name in groups:
+ for name in doctype_cache_keys:
cache.hdel(name, dt)
if doctype:
@@ -84,9 +87,31 @@ def clear_doctype_cache(doctype=None):
else:
# clear all
- for name in groups:
+ for name in doctype_cache_keys:
cache.delete_value(name)
# Clear all document's cache. To clear documents of a specific DocType document_cache should be restructured
clear_document_cache()
+def get_doctype_map(doctype, name, filters, order_by=None):
+ cache = frappe.cache()
+ cache_key = frappe.scrub(doctype) + '_map'
+ doctype_map = cache.hget(cache_key, name)
+
+ if doctype_map:
+ # cached, return
+ items = json.loads(doctype_map)
+ else:
+ # non cached, build cache
+ try:
+ items = frappe.get_all(doctype, filters=filters, order_by = order_by)
+ cache.hset(cache_key, doctype, json.dumps(items))
+ except frappe.db.TableMissingError:
+ # executed from inside patch, ignore
+ items = []
+
+ return items
+
+def clear_doctype_map(doctype, name):
+ cache_key = frappe.scrub(doctype) + '_map'
+ frappe.cache().hdel(cache_key, name)
\ No newline at end of file
diff --git a/frappe/chat/doctype/chat_profile/chat_profile.py b/frappe/chat/doctype/chat_profile/chat_profile.py
index e922cb28e2..698d992d35 100644
--- a/frappe/chat/doctype/chat_profile/chat_profile.py
+++ b/frappe/chat/doctype/chat_profile/chat_profile.py
@@ -17,10 +17,6 @@ from frappe.chat.util import (
session = frappe.session
class ChatProfile(Document):
- def before_save(self):
- if not self.is_new():
- self.get_doc_before_save()
-
def on_update(self):
if not self.is_new():
b, a = self.get_doc_before_save(), self
diff --git a/frappe/chat/doctype/chat_room/chat_room.py b/frappe/chat/doctype/chat_room/chat_room.py
index db138ed08b..b5873fa2d0 100644
--- a/frappe/chat/doctype/chat_room/chat_room.py
+++ b/frappe/chat/doctype/chat_room/chat_room.py
@@ -69,10 +69,6 @@ class ChatRoom(Document):
if self.type == "Group" and not self.room_name:
frappe.throw(_('Group name cannot be empty.'))
- def before_save(self):
- if not self.is_new():
- self.get_doc_before_save()
-
def on_update(self):
if not self.is_new():
before = self.get_doc_before_save()
diff --git a/frappe/client.py b/frappe/client.py
index fb2d47925b..3f7491ade5 100644
--- a/frappe/client.py
+++ b/frappe/client.py
@@ -371,4 +371,5 @@ def check_parent_permission(parent, child_doctype):
if frappe.permissions.has_permission(parent):
return
# Either parent not passed or the user doesn't have permission on parent doctype of child table!
- raise frappe.PermissionError
\ No newline at end of file
+ raise frappe.PermissionError
+
diff --git a/frappe/commands/site.py b/frappe/commands/site.py
index 3798c07e91..ee8131c1dc 100755
--- a/frappe/commands/site.py
+++ b/frappe/commands/site.py
@@ -157,16 +157,17 @@ def _reinstall(site, admin_password=None, mariadb_root_username=None, mariadb_ro
admin_password=admin_password)
@click.command('install-app')
-@click.argument('app')
+@click.argument('apps', nargs=-1)
@pass_context
-def install_app(context, app):
- "Install a new app to site"
+def install_app(context, apps):
+ "Install a new app to site, supports multiple apps"
from frappe.installer import install_app as _install_app
for site in context.sites:
frappe.init(site=site)
frappe.connect()
try:
- _install_app(app, verbose=context.verbose)
+ for app in apps:
+ _install_app(app, verbose=context.verbose)
finally:
frappe.destroy()
diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py
index ab8597832d..219a99070b 100644
--- a/frappe/commands/utils.py
+++ b/frappe/commands/utils.py
@@ -625,19 +625,30 @@ def setup_help(context):
print_in_app_help_deprecation()
@click.command('rebuild-global-search')
+@click.option('--static-pages', is_flag=True, default=False, help='Rebuild global search for static pages')
@pass_context
-def rebuild_global_search(context):
+def rebuild_global_search(context, static_pages=False):
'''Setup help table in the current site (called after migrate)'''
- from frappe.utils.global_search import (get_doctypes_with_global_search, rebuild_for_doctype)
+ from frappe.utils.global_search import (get_doctypes_with_global_search, rebuild_for_doctype,
+ get_routes_to_index, add_route_to_global_search, sync_global_search)
for site in context.sites:
try:
frappe.init(site)
frappe.connect()
- doctypes = get_doctypes_with_global_search()
- for i, doctype in enumerate(doctypes):
- rebuild_for_doctype(doctype)
- update_progress_bar('Rebuilding Global Search', i, len(doctypes))
+
+ if static_pages:
+ routes = get_routes_to_index()
+ for i, route in enumerate(routes):
+ add_route_to_global_search(route)
+ frappe.local.request = None
+ update_progress_bar('Rebuilding Global Search', i, len(routes))
+ sync_global_search()
+ else:
+ doctypes = get_doctypes_with_global_search()
+ for i, doctype in enumerate(doctypes):
+ rebuild_for_doctype(doctype)
+ update_progress_bar('Rebuilding Global Search', i, len(doctypes))
finally:
frappe.destroy()
diff --git a/frappe/config/__init__.py b/frappe/config/__init__.py
index 1fe06f9094..b2c1f41d78 100644
--- a/frappe/config/__init__.py
+++ b/frappe/config/__init__.py
@@ -78,15 +78,22 @@ def get_modules_from_app(app):
return active_modules_list
def get_all_empty_tables_by_module():
- results = frappe.db.sql("""
- SELECT
- name, module
- FROM information_schema.tables as i
- JOIN tabDocType as d
- ON i.table_name = CONCAT('tab', d.name)
- WHERE table_rows = 0;
-
- """)
+ results = frappe.db.multisql({
+ 'mariadb': '''
+ SELECT `name`, `module`
+ FROM information_schema.tables AS i
+ JOIN `tabDocType` AS d
+ ON i.table_name = CONCAT('tab', d.name)
+ WHERE `table_rows` = 0;
+ ''',
+ 'postgres': '''
+ SELECT "name", "module"
+ FROM "pg_stat_all_tables" AS i
+ JOIN "tabDocType" AS d
+ ON i.relname = CONCAT('tab', d.name)
+ WHERE n_tup_ins = 0;
+ '''
+ })
empty_tables_by_module = {}
@@ -95,7 +102,6 @@ def get_all_empty_tables_by_module():
empty_tables_by_module[module].append(doctype)
else:
empty_tables_by_module[module] = [doctype]
-
return empty_tables_by_module
def is_domain(module):
diff --git a/frappe/contacts/address_and_contact.py b/frappe/contacts/address_and_contact.py
index 38d292e9b4..6523b0b1e5 100644
--- a/frappe/contacts/address_and_contact.py
+++ b/frappe/contacts/address_and_contact.py
@@ -152,3 +152,11 @@ def filter_dynamic_link_doctypes(doctype, txt, searchfield, start, page_len, fil
valid_doctypes = [[doctype] for doctype in valid_doctypes]
return valid_doctypes
+
+def set_link_title(doc):
+ if not doc.links:
+ return
+ for link in doc.links:
+ if not link.link_title:
+ linked_doc = frappe.get_doc(link.link_doctype, link.link_name)
+ link.link_title = linked_doc.get("title_field") or linked_doc.get("name")
diff --git a/frappe/contacts/doctype/address/address.py b/frappe/contacts/doctype/address/address.py
index c705f972d3..57ed4e937f 100644
--- a/frappe/contacts/doctype/address/address.py
+++ b/frappe/contacts/doctype/address/address.py
@@ -15,6 +15,7 @@ from frappe.model.naming import make_autoname
from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_links
from six import iteritems, string_types
from past.builtins import cmp
+from frappe.contacts.address_and_contact import set_link_title
import functools
@@ -39,6 +40,7 @@ class Address(Document):
def validate(self):
self.link_address()
self.validate_reference()
+ set_link_title(self)
deduplicate_dynamic_links(self)
def link_address(self):
diff --git a/frappe/contacts/doctype/contact/contact.py b/frappe/contacts/doctype/contact/contact.py
index 987fad3829..0e0d9aeabc 100644
--- a/frappe/contacts/doctype/contact/contact.py
+++ b/frappe/contacts/doctype/contact/contact.py
@@ -10,6 +10,7 @@ from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_li
from six import iteritems
from past.builtins import cmp
from frappe.model.naming import append_number_if_name_exists
+from frappe.contacts.address_and_contact import set_link_title
import functools
@@ -31,6 +32,7 @@ class Contact(Document):
if self.email_id:
self.email_id = self.email_id.strip()
self.set_user()
+ set_link_title(self)
if self.email_id and not self.image:
self.image = has_gravatar(self.email_id)
diff --git a/frappe/core/doctype/activity_log/activity_log.py b/frappe/core/doctype/activity_log/activity_log.py
index 7badf737e4..8b7941c086 100644
--- a/frappe/core/doctype/activity_log/activity_log.py
+++ b/frappe/core/doctype/activity_log/activity_log.py
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
from frappe import _
from frappe.utils import get_fullname, now
from frappe.model.document import Document
-from frappe.core.utils import get_parent_doc, set_timeline_doc
+from frappe.core.utils import set_timeline_doc
import frappe
class ActivityLog(Document):
diff --git a/frappe/core/doctype/activity_log/feed.py b/frappe/core/doctype/activity_log/feed.py
index e09436196e..8892038681 100644
--- a/frappe/core/doctype/activity_log/feed.py
+++ b/frappe/core/doctype/activity_log/feed.py
@@ -67,7 +67,7 @@ def get_feed_match_conditions(user=None, doctype='Comment'):
user_permissions = frappe.permissions.get_user_permissions(user)
can_read = frappe.get_user().get_can_read()
- can_read_doctypes = ['"{}"'.format(doctype) for doctype in
+ can_read_doctypes = ["'{}'".format(doctype) for doctype in
list(set(can_read) - set(list(user_permissions)))]
if can_read_doctypes:
diff --git a/frappe/core/doctype/comment/test_comment.py b/frappe/core/doctype/comment/test_comment.py
index 2f6583b7ba..2adc5eb899 100644
--- a/frappe/core/doctype/comment/test_comment.py
+++ b/frappe/core/doctype/comment/test_comment.py
@@ -48,10 +48,10 @@ class TestComment(unittest.TestCase):
add_comment('pleez vizits my site http://mysite.com', 'test@test.com', 'bad commentor',
'Blog Post', test_blog.name, test_blog.route)
- self.assertEqual(frappe.get_all('Comment', fields = ['*'], filters = dict(
+ self.assertEqual(len(frappe.get_all('Comment', fields = ['*'], filters = dict(
reference_doctype = test_blog.doctype,
reference_name = test_blog.name
- ))[0].published, 0)
+ ))), 0)
diff --git a/frappe/core/doctype/communication/communication.js b/frappe/core/doctype/communication/communication.js
index 8e35c388a5..924c29bee2 100644
--- a/frappe/core/doctype/communication/communication.js
+++ b/frappe/core/doctype/communication/communication.js
@@ -31,13 +31,6 @@ frappe.ui.form.on("Communication", {
}
}
- if(frm.doc.communication_type == "Feedback") {
- frm.add_custom_button(__("Resend"), function() {
- var feedback = new frappe.utils.Feedback();
- feedback.resend_feedback_request(frm.doc);
- });
- }
-
if(frm.doc.status==="Open") {
frm.add_custom_button(__("Close"), function() {
frm.set_value("status", "Closed");
@@ -54,7 +47,7 @@ frappe.ui.form.on("Communication", {
frm.trigger('show_relink_dialog');
});
- if(frm.doc.communication_type=="Communication"
+ if(frm.doc.communication_type=="Communication"
&& frm.doc.communication_medium == "Email"
&& frm.doc.sent_or_received == "Received") {
@@ -90,7 +83,7 @@ frappe.ui.form.on("Communication", {
}
}
- if(frm.doc.communication_type=="Communication"
+ if(frm.doc.communication_type=="Communication"
&& frm.doc.communication_medium == "Phone"
&& frm.doc.sent_or_received == "Received"){
@@ -185,7 +178,7 @@ frappe.ui.form.on("Communication", {
forward_mail: function(frm) {
var args = frm.events.get_mail_args(frm)
- $.extend(args, {
+ $.extend(args, {
forward: true,
subject: __("Fw: {0}", [frm.doc.subject]),
})
diff --git a/frappe/core/doctype/communication/communication.json b/frappe/core/doctype/communication/communication.json
index ea0e429e0f..68a0adb634 100644
--- a/frappe/core/doctype/communication/communication.json
+++ b/frappe/core/doctype/communication/communication.json
@@ -1,1728 +1,438 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "",
- "beta": 0,
- "creation": "2013-01-29 10:47:14",
- "custom": 0,
- "description": "Keep a track of all communications",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "allow_import": 1,
+ "creation": "2013-01-29 10:47:14",
+ "description": "Keeps track of all communications",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "subject",
+ "section_break_10",
+ "communication_medium",
+ "sender",
+ "column_break_4",
+ "recipients",
+ "cc",
+ "bcc",
+ "phone_no",
+ "delivery_status",
+ "section_break_8",
+ "content",
+ "status_section",
+ "text_content",
+ "communication_type",
+ "comment_type",
+ "column_break_5",
+ "status",
+ "sent_or_received",
+ "additional_info",
+ "communication_date",
+ "read_receipt",
+ "column_break_14",
+ "sender_full_name",
+ "read_by_recipient",
+ "read_by_recipient_on",
+ "reference_section",
+ "reference_doctype",
+ "reference_name",
+ "reference_owner",
+ "email_account",
+ "in_reply_to",
+ "user",
+ "column_break_27",
+ "email_template",
+ "unread_notification_sent",
+ "seen",
+ "_user_tags",
+ "timeline_links_sections",
+ "timeline_links",
+ "email_inbox",
+ "message_id",
+ "uid",
+ "email_status",
+ "has_attachment",
+ "feedback_section",
+ "rating",
+ "feedback_request"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "subject",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Subject",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "subject",
+ "fieldtype": "Small Text",
+ "in_global_search": 1,
+ "label": "Subject",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "",
- "columns": 0,
- "fieldname": "section_break_10",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "To and CC",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "section_break_10",
+ "fieldtype": "Section Break",
+ "label": "To and CC"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "depends_on": "eval:doc.communication_type===\"Communication\"",
- "fieldname": "communication_medium",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Type",
- "length": 0,
- "no_copy": 0,
- "options": "\nEmail\nChat\nPhone\nSMS\nEvent\nMeeting\nVisit\nOther",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.communication_type===\"Communication\"",
+ "fieldname": "communication_medium",
+ "fieldtype": "Select",
+ "label": "Type",
+ "options": "\nEmail\nChat\nPhone\nSMS\nEvent\nMeeting\nVisit\nOther"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.communication_medium===\"Email\"",
- "fieldname": "sender",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From",
- "length": 255,
- "no_copy": 0,
- "options": "Email",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.communication_medium===\"Email\"",
+ "fieldname": "sender",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "From",
+ "length": 255,
+ "options": "Email"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "recipients",
- "fieldtype": "Code",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "To",
- "length": 0,
- "no_copy": 0,
- "options": "Email",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "recipients",
+ "fieldtype": "Code",
+ "label": "To",
+ "options": "Email"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.communication_medium===\"Email\"",
- "fieldname": "cc",
- "fieldtype": "Code",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "CC",
- "length": 0,
- "no_copy": 0,
- "options": "Email",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.communication_medium===\"Email\"",
+ "fieldname": "cc",
+ "fieldtype": "Code",
+ "label": "CC",
+ "options": "Email"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.communication_medium===\"Email\"",
- "fieldname": "bcc",
- "fieldtype": "Code",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "BCC",
- "length": 0,
- "no_copy": 0,
- "options": "Email",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.communication_medium===\"Email\"",
+ "fieldname": "bcc",
+ "fieldtype": "Code",
+ "label": "BCC",
+ "options": "Email"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:in_list([\"Phone\",\"SMS\"],doc.communication_medium)",
- "fieldname": "phone_no",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Phone No.",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:in_list([\"Phone\",\"SMS\"],doc.communication_medium)",
+ "fieldname": "phone_no",
+ "fieldtype": "Data",
+ "label": "Phone No."
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Integrations can use this field to set email delivery status",
- "fieldname": "delivery_status",
- "fieldtype": "Select",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Delivery Status",
- "length": 0,
- "no_copy": 0,
- "options": "\nSent\nBounced\nOpened\nMarked As Spam\nRejected\nDelayed\nSoft-Bounced\nClicked\nRecipient Unsubscribed\nError\nExpired\nSending\nRead",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "description": "Integrations can use this field to set email delivery status",
+ "fieldname": "delivery_status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "label": "Delivery Status",
+ "options": "\nSent\nBounced\nOpened\nMarked As Spam\nRejected\nDelayed\nSoft-Bounced\nClicked\nRecipient Unsubscribed\nError\nExpired\nSending\nRead"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_8",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "content",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Message",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "content",
+ "fieldtype": "Text Editor",
+ "label": "Message",
"width": "400"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "status_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "status_section",
+ "fieldtype": "Section Break",
+ "label": "Status"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "text_content",
- "fieldtype": "Code",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Text Content",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "text_content",
+ "fieldtype": "Code",
+ "hidden": 1,
+ "label": "Text Content"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Communication",
- "fieldname": "communication_type",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Communication Type",
- "length": 0,
- "no_copy": 0,
- "options": "Communication\nComment\nChat\nBot\nNotification\nFeedback",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Communication",
+ "fieldname": "communication_type",
+ "fieldtype": "Select",
+ "label": "Communication Type",
+ "options": "Communication\nComment\nChat\nBot\nNotification\nFeedback",
+ "read_only": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "comment_type",
- "fieldtype": "Select",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Comment Type",
- "length": 0,
- "no_copy": 0,
- "options": "\nComment\nLike\nInfo\nLabel\nWorkflow\nCreated\nSubmitted\nCancelled\nUpdated\nDeleted\nAssigned\nAssignment Completed\nAttachment\nAttachment Removed\nShared\nUnshared\nBot\nRelinked",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "comment_type",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Comment Type",
+ "options": "\nComment\nLike\nInfo\nLabel\nWorkflow\nCreated\nSubmitted\nCancelled\nUpdated\nDeleted\nAssigned\nAssignment Completed\nAttachment\nAttachment Removed\nShared\nUnshared\nBot\nRelinked",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_5",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.communication_type===\"Communication\"",
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Status",
- "length": 0,
- "no_copy": 0,
- "options": "Open\nReplied\nClosed\nLinked",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.communication_type===\"Communication\"",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Status",
+ "options": "Open\nReplied\nClosed\nLinked",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.communication_type===\"Communication\"",
- "fieldname": "sent_or_received",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Sent or Received",
- "length": 0,
- "no_copy": 0,
- "options": "Sent\nReceived",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.communication_type===\"Communication\"",
+ "fieldname": "sent_or_received",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Sent or Received",
+ "options": "Sent\nReceived",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "additional_info",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "More Information",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "additional_info",
+ "fieldtype": "Section Break",
+ "label": "More Information"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Now",
- "fieldname": "communication_date",
- "fieldtype": "Datetime",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Now",
+ "fieldname": "communication_date",
+ "fieldtype": "Datetime",
+ "label": "Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "read_receipt",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sent Read Receipt",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "read_receipt",
+ "fieldtype": "Check",
+ "label": "Sent Read Receipt",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_14",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_14",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sender_full_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From Full Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "sender_full_name",
+ "fieldtype": "Data",
+ "label": "From Full Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "read_by_recipient",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Read by Recipient",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "read_by_recipient",
+ "fieldtype": "Check",
+ "label": "Read by Recipient",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "read_by_recipient_on",
- "fieldtype": "Datetime",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Read by Recipient On",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "read_by_recipient_on",
+ "fieldtype": "Datetime",
+ "label": "Read by Recipient On",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "reference_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Reference",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "reference_section",
+ "fieldtype": "Section Break",
+ "label": "Reference"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reference_doctype",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Reference DocType",
- "length": 0,
- "no_copy": 0,
- "options": "DocType",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "reference_doctype",
+ "fieldtype": "Link",
+ "label": "Reference DocType",
+ "options": "DocType"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reference_name",
- "fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Reference Name",
- "length": 0,
- "no_copy": 0,
- "options": "reference_doctype",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "reference_name",
+ "fieldtype": "Dynamic Link",
+ "label": "Reference Name",
+ "options": "reference_doctype"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "reference_name.owner",
- "fieldname": "reference_owner",
- "fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Reference Owner",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "reference_name.owner",
+ "fieldname": "reference_owner",
+ "fieldtype": "Read Only",
+ "label": "Reference Owner",
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.communication_medium===\"Email\"",
- "fieldname": "email_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Email Account",
- "length": 0,
- "no_copy": 0,
- "options": "Email Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.communication_medium===\"Email\"",
+ "fieldname": "email_account",
+ "fieldtype": "Link",
+ "label": "Email Account",
+ "options": "Email Account",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "in_reply_to",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "In Reply To",
- "length": 0,
- "no_copy": 0,
- "options": "Communication",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "in_reply_to",
+ "fieldtype": "Link",
+ "label": "In Reply To",
+ "options": "Communication",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "__user",
- "fieldname": "user",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "User",
- "length": 0,
- "no_copy": 0,
- "options": "User",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "__user",
+ "fieldname": "user",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "User",
+ "options": "User",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_27",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_27",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "link_doctype",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Link DocType",
- "length": 0,
- "no_copy": 0,
- "options": "DocType",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "unread_notification_sent",
+ "fieldtype": "Check",
+ "label": "Unread Notification Sent",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "link_name",
- "fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Link Name",
- "length": 0,
- "no_copy": 0,
- "options": "link_doctype",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "seen",
+ "fieldtype": "Check",
+ "label": "Seen",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "timeline_doctype",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Timeline DocType",
- "length": 0,
- "no_copy": 0,
- "options": "DocType",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "_user_tags",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "User Tags",
+ "no_copy": 1,
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "timeline_name",
- "fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Timeline Name",
- "length": 0,
- "no_copy": 0,
- "options": "timeline_doctype",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "email_inbox",
+ "fieldtype": "Section Break",
+ "label": "Email Inbox",
+ "permlevel": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "timeline_label",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Timeline field Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "message_id",
+ "fieldtype": "Data",
+ "ignore_xss_filter": 1,
+ "label": "Message ID",
+ "length": 995,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "unread_notification_sent",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Unread Notification Sent",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "uid",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "label": "UID",
+ "no_copy": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "seen",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Seen",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "email_status",
+ "fieldtype": "Select",
+ "label": "Email Status",
+ "options": "Open\nSpam\nTrash"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "_user_tags",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "User Tags",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "has_attachment",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Has Attachment"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "email_inbox",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Email Inbox",
- "length": 0,
- "no_copy": 0,
- "permlevel": 1,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "depends_on": "eval: doc.rating > 0",
+ "fieldname": "feedback_section",
+ "fieldtype": "Section Break",
+ "label": "Feedback"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "message_id",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 1,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Message ID",
- "length": 995,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "rating",
+ "fieldtype": "Int",
+ "label": "Rating",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "uid",
- "fieldtype": "Int",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "UID",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "feedback_request",
+ "fieldtype": "Data",
+ "label": "Feedback Request",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "email_status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Email Status",
- "length": 0,
- "no_copy": 0,
- "options": "Open\nSpam\nTrash",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "email_template",
+ "fieldtype": "Link",
+ "label": "Email Template",
+ "options": "Email Template",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "has_attachment",
- "fieldtype": "Check",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Has Attachment",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "timeline_links_sections",
+ "fieldtype": "Section Break",
+ "label": "Timeline Links"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "depends_on": "eval: doc.rating > 0",
- "fieldname": "feedback_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Feedback",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rating",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rating",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "feedback_request",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Feedback Request",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "timeline_links",
+ "fieldtype": "Table",
+ "label": "Timeline Links",
+ "options": "Dynamic Link",
+ "permlevel": 2
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-comment",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-09-24 13:53:52.389244",
- "modified_by": "chdecultot@dokos.io",
- "module": "Core",
- "name": "Communication",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-comment",
+ "idx": 1,
+ "modified": "2019-05-20 14:14:01.514493",
+ "modified_by": "Administrator",
+ "module": "Core",
+ "name": "Communication",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 0
- },
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 0
- },
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "permlevel": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 1,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "All",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "permlevel": 2,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "delete": 1,
+ "email": 1,
+ "if_owner": 1,
+ "read": 1,
+ "role": "All"
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "subject",
- "show_name_in_global_search": 0,
- "sort_order": "DESC",
- "title_field": "subject",
- "track_changes": 1,
- "track_seen": 1,
- "track_views": 0
+ ],
+ "search_fields": "subject",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "subject",
+ "track_changes": 1,
+ "track_seen": 1
}
\ No newline at end of file
diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py
index 77ccefba71..0fb2efc7ec 100644
--- a/frappe/core/doctype/communication/communication.py
+++ b/frappe/core/doctype/communication/communication.py
@@ -8,11 +8,11 @@ from frappe.model.document import Document
from frappe.utils import validate_email_address, get_fullname, strip_html, cstr
from frappe.core.doctype.communication.email import (validate_email,
notify, _notify, update_parent_mins_to_first_response)
-from frappe.core.utils import get_parent_doc, set_timeline_doc
+from frappe.core.utils import get_parent_doc
from frappe.utils.bot import BotReply
from frappe.utils import parse_addr
from frappe.core.doctype.comment.comment import update_comment_in_doc
-
+from email.utils import parseaddr
from collections import Counter
exclude_from_linked_with = True
@@ -58,7 +58,10 @@ class Communication(Document):
self.set_sender_full_name()
validate_email(self)
- set_timeline_doc(self)
+
+ if self.communication_medium == "Email":
+ self.set_timeline_links()
+ self.deduplicate_timeline_links()
def validate_reference(self):
if self.reference_doctype and self.reference_name:
@@ -79,6 +82,7 @@ class Communication(Document):
circular_linking = True
break
doc = get_parent_doc(doc)
+
if circular_linking:
frappe.throw(_("Please make sure the Reference Communication Docs are not circularly linked."), frappe.CircularLinkingError)
@@ -231,26 +235,66 @@ class Communication(Document):
if commit:
frappe.db.commit()
+ # Timeline Links
+ def set_timeline_links(self):
+ contacts = get_contacts([self.sender, self.recipients, self.cc, self.bcc])
+ for contact_name in contacts:
+ self.add_link('Contact', contact_name)
+
+ #link contact's dynamic links to communication
+ add_contact_links_to_communication(self, contact_name)
+
+ def deduplicate_timeline_links(self):
+ if self.timeline_links:
+ links, duplicate = [], False
+
+ for l in self.timeline_links:
+ t = (l.link_doctype, l.link_name)
+ if not t in links:
+ links.append(t)
+ else:
+ duplicate = True
+
+ if duplicate:
+ del self.timeline_links[:] # make it python 2 compatible as list.clear() is python 3 only
+ for l in links:
+ self.add_link(link_doctype=l[0], link_name=l[1])
+
+ def add_link(self, link_doctype, link_name, autosave=False):
+ self.append("timeline_links",
+ {
+ "link_doctype": link_doctype,
+ "link_name": link_name
+ }
+ )
+
+ if autosave:
+ self.save(ignore_permissions=True)
+
+ def get_links(self):
+ return self.timeline_links
+
+ def remove_link(self, link_doctype, link_name, autosave=False, ignore_permissions=True):
+ for l in self.timeline_links:
+ if l.link_doctype == link_doctype and l.link_name == link_name:
+ self.timeline_links.remove(l)
+
+ if autosave:
+ self.save(ignore_permissions=ignore_permissions)
def on_doctype_update():
"""Add indexes in `tabCommunication`"""
frappe.db.add_index("Communication", ["reference_doctype", "reference_name"])
- frappe.db.add_index("Communication", ["timeline_doctype", "timeline_name"])
- frappe.db.add_index("Communication", ["link_doctype", "link_name"])
frappe.db.add_index("Communication", ["status", "communication_type"])
def has_permission(doc, ptype, user):
if ptype=="read":
- if (doc.reference_doctype == "Communication" and doc.reference_name == doc.name) \
- or (doc.timeline_doctype == "Communication" and doc.timeline_name == doc.name):
- return
+ if doc.reference_doctype == "Communication" and doc.reference_name == doc.name:
+ return
if doc.reference_doctype and doc.reference_name:
if frappe.has_permission(doc.reference_doctype, ptype="read", doc=doc.reference_name):
return True
- if doc.timeline_doctype and doc.timeline_name:
- if frappe.has_permission(doc.timeline_doctype, ptype="read", doc=doc.timeline_name):
- return True
def get_permission_query_conditions_for_communication(user):
if not user: user = frappe.session.user
@@ -265,8 +309,44 @@ def get_permission_query_conditions_for_communication(user):
distinct=True, order_by="idx")
if not accounts:
- return """tabCommunication.communication_medium!='Email'"""
+ return """`tabCommunication`.communication_medium!='Email'"""
email_accounts = [ '"%s"'%account.get("email_account") for account in accounts ]
- return """tabCommunication.email_account in ({email_accounts})"""\
+ return """`tabCommunication`.email_account in ({email_accounts})"""\
.format(email_accounts=','.join(email_accounts))
+
+def get_contacts(email_strings):
+ email_addrs = []
+
+ for email_string in email_strings:
+ if email_string:
+ for email in email_string.split(","):
+ parsed_email = parseaddr(email)[1]
+ if parsed_email:
+ email_addrs.append(parsed_email)
+
+ contacts = []
+ for email in email_addrs:
+ contact_name = frappe.db.get_value('Contact', {'email_id': email})
+
+ if not contact_name:
+ contact = frappe.get_doc({
+ "doctype": "Contact",
+ "first_name": frappe.unscrub(email.split("@")[0]),
+ "email_id": email
+ }).insert(ignore_permissions=True)
+ contact_name = contact.name
+
+ contacts.append(contact_name)
+
+ return contacts
+
+def add_contact_links_to_communication(communication, contact_name):
+ contact_links = frappe.get_list("Dynamic Link", filters={
+ "parenttype": "Contact",
+ "parent": contact_name
+ }, fields=["link_doctype", "link_name"])
+
+ if contact_links:
+ for contact_link in contact_links:
+ communication.add_link(contact_link.link_doctype, contact_link.link_name)
\ No newline at end of file
diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py
index 0048668ee2..36377a90f7 100755
--- a/frappe/core/doctype/communication/email.py
+++ b/frappe/core/doctype/communication/email.py
@@ -22,7 +22,7 @@ from frappe.utils.background_jobs import enqueue
def make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent",
sender=None, sender_full_name=None, recipients=None, communication_medium="Email", send_email=False,
print_html=None, print_format=None, attachments='[]', send_me_a_copy=False, cc=None, bcc=None,
- flags=None, read_receipt=None, print_letterhead=True):
+ flags=None, read_receipt=None, print_letterhead=True, email_template=None):
"""Make a new communication.
:param doctype: Reference DocType.
@@ -38,6 +38,7 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received =
:param print_format: Print Format name of parent document to be sent as attachment.
:param attachments: List of attachments as list of files or JSON string.
:param send_me_a_copy: Send a copy to the sender (default **False**).
+ :param email_template: Template which is used to compose mail .
"""
is_error_report = (doctype=="User" and name==frappe.session.user and subject=="Error Report")
@@ -66,15 +67,13 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received =
"sent_or_received": sent_or_received,
"reference_doctype": doctype,
"reference_name": name,
+ "email_template": email_template,
"message_id":get_message_id().strip(" <>"),
"read_receipt":read_receipt,
"has_attachment": 1 if attachments else 0
- })
- comm.insert(ignore_permissions=True)
+ }).insert(ignore_permissions=True)
- if not doctype:
- # if no reference given, then send it against the communication
- comm.db_set(dict(reference_doctype='Communication', reference_name=comm.name))
+ comm.save(ignore_permissions=True)
if isinstance(attachments, string_types):
attachments = json.loads(attachments)
@@ -555,5 +554,4 @@ def mark_email_as_seen(name=None):
frappe.response["type"] = 'binary'
frappe.response["filename"] = "imaginary_pixel.png"
- frappe.response["filecontent"] = buffered_obj.getvalue()
-
+ frappe.response["filecontent"] = buffered_obj.getvalue()
\ No newline at end of file
diff --git a/frappe/core/doctype/communication/test_communication.py b/frappe/core/doctype/communication/test_communication.py
index 1941ff31cc..a783157dc0 100644
--- a/frappe/core/doctype/communication/test_communication.py
+++ b/frappe/core/doctype/communication/test_communication.py
@@ -44,28 +44,126 @@ class TestCommunication(unittest.TestCase):
self.assertFalse(frappe.utils.parse_addr(x)[0])
def test_circular_linking(self):
- content = "This was created to test circular linking"
a = frappe.get_doc({
"doctype": "Communication",
"communication_type": "Communication",
- "content": content,
- }).insert()
+ "content": "This was created to test circular linking: Communication A",
+ }).insert(ignore_permissions=True)
+
b = frappe.get_doc({
"doctype": "Communication",
"communication_type": "Communication",
- "content": content,
+ "content": "This was created to test circular linking: Communication B",
"reference_doctype": "Communication",
"reference_name": a.name
- }).insert()
+ }).insert(ignore_permissions=True)
+
c = frappe.get_doc({
"doctype": "Communication",
"communication_type": "Communication",
- "content": content,
+ "content": "This was created to test circular linking: Communication C",
"reference_doctype": "Communication",
"reference_name": b.name
- }).insert()
+ }).insert(ignore_permissions=True)
+
a = frappe.get_doc("Communication", a.name)
a.reference_doctype = "Communication"
a.reference_name = c.name
+
self.assertRaises(frappe.CircularLinkingError, a.save)
+ def test_deduplication_timeline_links(self):
+ note = frappe.get_doc({
+ "doctype": "Note",
+ "title": "deduplication timeline links",
+ "content": "deduplication timeline links"
+ }).insert(ignore_permissions=True)
+
+ comm = frappe.get_doc({
+ "doctype": "Communication",
+ "communication_type": "Communication",
+ "content": "Deduplication of Links",
+ "communication_medium": "Email"
+ }).insert(ignore_permissions=True)
+
+ #adding same link twice
+ comm.add_link(link_doctype="Note", link_name=note.name, autosave=True)
+ comm.add_link(link_doctype="Note", link_name=note.name, autosave=True)
+
+ comm = frappe.get_doc("Communication", comm.name)
+
+ self.assertNotEqual(2, len(comm.timeline_links))
+
+ def test_contacts_attached(self):
+ contact_sender = frappe.get_doc({
+ "doctype": "Contact",
+ "first_name": frappe.generate_hash(length=10),
+ "email_id": "comm_sender@example.com"
+ }).insert(ignore_permissions=True)
+
+ contact_recipient = frappe.get_doc({
+ "doctype": "Contact",
+ "first_name": frappe.generate_hash(length=10),
+ "email_id": "comm_recipient@example.com"
+ }).insert(ignore_permissions=True)
+
+ contact_cc = frappe.get_doc({
+ "doctype": "Contact",
+ "first_name": frappe.generate_hash(length=10),
+ "email_id": "comm_cc@example.com"
+ }).insert(ignore_permissions=True)
+
+ comm = frappe.get_doc({
+ "doctype": "Communication",
+ "communication_medium": "Email",
+ "subject": "Contacts Attached Test",
+ "sender": "comm_sender@example.com",
+ "recipients": "comm_recipient@example.com",
+ "cc": "comm_cc@example.com"
+ }).insert(ignore_permissions=True)
+
+ comm = frappe.get_doc("Communication", comm.name)
+
+ contact_links = []
+ for timeline_link in comm.timeline_links:
+ contact_links.append(timeline_link.link_name)
+
+ self.assertIn(contact_sender.name, contact_links)
+ self.assertIn(contact_recipient.name, contact_links)
+ self.assertIn(contact_cc.name, contact_links)
+
+ def test_get_communication_data(self):
+ from frappe.desk.form.load import get_communication_data
+
+ note = frappe.get_doc({
+ "doctype": "Note",
+ "title": "get communication data",
+ "content": "get communication data"
+ }).insert(ignore_permissions=True)
+
+ comm_note_1 = frappe.get_doc({
+ "doctype": "Communication",
+ "communication_type": "Communication",
+ "content": "Test Get Communication Data 1",
+ "communication_medium": "Email"
+ }).insert(ignore_permissions=True)
+
+ comm_note_1.add_link(link_doctype="Note", link_name=note.name, autosave=True)
+
+ comm_note_2 = frappe.get_doc({
+ "doctype": "Communication",
+ "communication_type": "Communication",
+ "content": "Test Get Communication Data 2",
+ "communication_medium": "Email"
+ }).insert(ignore_permissions=True)
+
+ comm_note_2.add_link(link_doctype="Note", link_name=note.name, autosave=True)
+
+ comms = get_communication_data("Note", note.name, as_dict=True)
+
+ data = []
+ for comm in comms:
+ data.append(comm.name)
+
+ self.assertIn(comm_note_1.name, data)
+ self.assertIn(comm_note_2.name, data)
\ No newline at end of file
diff --git a/frappe/core/doctype/docfield/docfield.json b/frappe/core/doctype/docfield/docfield.json
index b295a9be66..c78495898e 100644
--- a/frappe/core/doctype/docfield/docfield.json
+++ b/frappe/core/doctype/docfield/docfield.json
@@ -30,6 +30,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
@@ -62,6 +63,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Label",
"length": 0,
@@ -99,13 +101,14 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Type",
"length": 0,
"no_copy": 0,
"oldfieldname": "fieldtype",
"oldfieldtype": "Select",
- "options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRating\nRead Only\nSection Break\nSelect\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime\nSignature",
+ "options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRead Only\nSection Break\nSelect\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime\nSignature",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -134,6 +137,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Name",
"length": 0,
@@ -168,6 +172,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Mandatory",
"length": 0,
@@ -206,6 +211,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Precision",
"length": 0,
@@ -240,6 +246,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Length",
"length": 0,
@@ -273,6 +280,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Index",
"length": 0,
@@ -309,6 +317,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "In List View",
"length": 0,
@@ -343,6 +352,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "In Standard Filter",
"length": 0,
@@ -377,6 +387,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "In Global Search",
"length": 0,
@@ -394,6 +405,40 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "in_preview",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_preview": 0,
+ "in_standard_filter": 0,
+ "label": "In Preview",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -410,6 +455,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Allow in Quick Entry",
"length": 0,
@@ -443,6 +489,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Bold",
"length": 0,
@@ -478,6 +525,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Translatable",
"length": 0,
@@ -512,6 +560,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Collapsible",
"length": 255,
@@ -546,6 +595,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Collapsible Depends On",
"length": 0,
@@ -580,6 +630,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
@@ -612,6 +663,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Options",
"length": 0,
@@ -646,6 +698,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Default",
"length": 0,
@@ -680,6 +733,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Fetch From",
"length": 0,
@@ -714,6 +768,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Fetch If Empty",
"length": 0,
@@ -747,6 +802,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Permissions",
"length": 0,
@@ -779,6 +835,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Display Depends On",
"length": 255,
@@ -814,6 +871,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Hidden",
"length": 0,
@@ -850,6 +908,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Read Only",
"length": 0,
@@ -884,6 +943,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Unique",
"length": 0,
@@ -918,6 +978,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Set Only Once",
"length": 0,
@@ -951,6 +1012,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Allow Bulk Edit",
"length": 0,
@@ -984,6 +1046,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
@@ -1016,6 +1079,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Perm Level",
"length": 0,
@@ -1053,6 +1117,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Ignore User Permissions",
"length": 0,
@@ -1086,6 +1151,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Allow on Submit",
"length": 0,
@@ -1122,6 +1188,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Report Hide",
"length": 0,
@@ -1159,6 +1226,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Remember Last Selected Value",
"length": 0,
@@ -1193,6 +1261,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Ignore XSS Filter",
"length": 0,
@@ -1226,6 +1295,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Display",
"length": 0,
@@ -1258,6 +1328,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "In Filter",
"length": 0,
@@ -1294,6 +1365,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "No Copy",
"length": 0,
@@ -1330,6 +1402,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Print Hide",
"length": 0,
@@ -1367,6 +1440,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Print Hide If No Value",
"length": 0,
@@ -1400,6 +1474,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Print Width",
"length": 0,
@@ -1432,6 +1507,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Width",
"length": 0,
@@ -1470,6 +1546,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Columns",
"length": 0,
@@ -1503,6 +1580,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
@@ -1534,6 +1612,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
+ "in_preview": 0,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
@@ -1570,6 +1649,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
@@ -1603,6 +1683,7 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
+ "in_preview": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
@@ -1622,16 +1703,14 @@
}
],
"has_web_view": 0,
- "hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
- "image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2019-03-18 17:59:57.873790",
+ "modified": "2019-04-08 12:19:53.415372",
"modified_by": "Administrator",
"module": "Core",
"name": "DocField",
@@ -1639,7 +1718,6 @@
"permissions": [],
"quick_entry": 0,
"read_only": 0,
- "read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_order": "ASC",
"track_changes": 0,
diff --git a/frappe/core/doctype/doctype/boilerplate/test_controller._py b/frappe/core/doctype/doctype/boilerplate/test_controller._py
index 44e030bd0e..8ed08ae15a 100644
--- a/frappe/core/doctype/doctype/boilerplate/test_controller._py
+++ b/frappe/core/doctype/doctype/boilerplate/test_controller._py
@@ -3,7 +3,7 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
+# import frappe
import unittest
class Test{classname}(unittest.TestCase):
diff --git a/frappe/core/doctype/doctype/doctype.json b/frappe/core/doctype/doctype/doctype.json
index 599427f740..24a7a4c287 100644
--- a/frappe/core/doctype/doctype/doctype.json
+++ b/frappe/core/doctype/doctype/doctype.json
@@ -1,1889 +1,457 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 1,
- "autoname": "Prompt",
- "beta": 0,
- "creation": "2013-02-18 13:36:19",
- "custom": 0,
- "description": "DocType is a Table / Form in the application.",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "sb0",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "module",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Module",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "module",
- "oldfieldtype": "Link",
- "options": "Module Def",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.istable",
- "description": "Once submitted, submittable documents cannot be changed. They can only be Cancelled and Amended.",
- "fetch_if_empty": 0,
- "fieldname": "is_submittable",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Submittable",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Child Tables are shown as a Grid in other DocTypes",
- "fetch_if_empty": 0,
- "fieldname": "istable",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Is Child Table",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "istable",
- "oldfieldtype": "Check",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.istable",
- "description": "Single Types have only one record no tables associated. Values are stored in tabSingles",
- "fetch_if_empty": 0,
- "fieldname": "issingle",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Is Single",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "issingle",
- "oldfieldtype": "Check",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 1,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "depends_on": "istable",
- "fetch_if_empty": 0,
- "fieldname": "editable_grid",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Editable Grid",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "depends_on": "eval:!doc.istable && !doc.issingle",
- "description": "Open a dialog with mandatory fields to create a new record quickly",
- "fetch_if_empty": 0,
- "fieldname": "quick_entry",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Quick Entry",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "cb01",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "depends_on": "eval:!doc.istable",
- "description": "If enabled, changes to the document are tracked and shown in timeline",
- "fetch_if_empty": 0,
- "fieldname": "track_changes",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Track Changes",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.istable",
- "description": "If enabled, the document is marked as seen, the first time a user opens it",
- "fetch_if_empty": 0,
- "fieldname": "track_seen",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Track Seen",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "depends_on": "eval:!doc.istable",
- "description": "If enabled, document views are tracked, this can happen multiple times",
- "fetch_if_empty": 0,
- "fieldname": "track_views",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Track Views",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "custom",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Custom?",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "beta",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Beta",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "fields_section_break",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Fields",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "fields",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Fields",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "fields",
- "oldfieldtype": "Table",
- "options": "DocField",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "sb1",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Naming",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Naming Options:\n
field:[fieldname] - By Fieldnaming_series: - By Naming Series (field called naming_series must be presentPrompt - Prompt user for a name[series] - Series by prefix (separated by a dot); for example PRE.##### \nformat:EXAMPLE-{MM}morewords{fieldname1}-{fieldname2}-{#####} - Replace all braced words (fieldnames, date words (DD, MM, YY), series) with their value. Outside braces, any characters can be used. ",
- "fetch_if_empty": 0,
- "fieldname": "autoname",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Auto Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "autoname",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "name_case",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Name Case",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "name_case",
- "oldfieldtype": "Select",
- "options": "\nTitle Case\nUPPER CASE",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "column_break_15",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "description",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "description",
- "oldfieldtype": "Text",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "form_settings_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Form Settings",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Must be of type \"Attach Image\"",
- "fetch_if_empty": 0,
- "fieldname": "image_field",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Image Field",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.istable",
- "description": "Comments and Communications will be associated with this linked document",
- "fetch_if_empty": 0,
- "fieldname": "timeline_field",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Timeline Field",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "max_attachments",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Max Attachments",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "max_attachments",
- "oldfieldtype": "Int",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_23",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "hide_toolbar",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Hide Sidebar and Menu",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "hide_toolbar",
- "oldfieldtype": "Check",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "allow_copy",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Hide Copy",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "allow_copy",
- "oldfieldtype": "Check",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "allow_rename",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Rename",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "allow_rename",
- "oldfieldtype": "Check",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "allow_import",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Import (via Data Import Tool)",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "allow_events_in_timeline",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow events in timeline",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "view_settings",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "View Settings",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.istable",
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "title_field",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Title Field",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.istable",
- "fetch_if_empty": 0,
- "fieldname": "search_fields",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Search Fields",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "search_fields",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "default_print_format",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Print Format",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "modified",
- "depends_on": "eval:!doc.istable",
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "sort_field",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Sort Field",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "DESC",
- "depends_on": "eval:!doc.istable",
- "fetch_if_empty": 0,
- "fieldname": "sort_order",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Sort Order",
- "length": 0,
- "no_copy": 0,
- "options": "ASC\nDESC",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "column_break_29",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "document_type",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Show in Module Section",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "document_type",
- "oldfieldtype": "Select",
- "options": "\nDocument\nSetup\nSystem\nOther",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "icon",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Icon",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "color",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Color",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "show_name_in_global_search",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Make \"name\" searchable in Global Search",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.istable",
- "fetch_if_empty": 0,
- "fieldname": "sb2",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Permission Rules",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "permissions",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Permissions",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "permissions",
- "oldfieldtype": "Table",
- "options": "DocPerm",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "restrict_to_domain",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Restrict To Domain",
- "length": 0,
- "no_copy": 0,
- "options": "Domain",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "read_only",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "User Cannot Search",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "read_only",
- "oldfieldtype": "Check",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "in_create",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "User Cannot Create",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "in_create",
- "oldfieldtype": "Check",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "web_view",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Web View",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fetch_if_empty": 0,
- "fieldname": "has_web_view",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Has Web View",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "depends_on": "has_web_view",
- "fetch_if_empty": 0,
- "fieldname": "allow_guest_to_view",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Guest to View",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "has_web_view",
- "fetch_if_empty": 0,
- "fieldname": "route",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Route",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "depends_on": "has_web_view",
- "fetch_if_empty": 0,
- "fieldname": "is_published_field",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Published Field",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "advanced",
- "fieldtype": "Section Break",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Advanced",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "InnoDB",
- "depends_on": "eval:!doc.issingle",
- "fetch_if_empty": 0,
- "fieldname": "engine",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Database Engine",
- "length": 0,
- "no_copy": 0,
- "options": "InnoDB\nMyISAM",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-bolt",
- "idx": 6,
- "image_field": "",
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2019-03-22 00:02:14.963400",
- "modified_by": "Administrator",
- "module": "Core",
- "name": "DocType",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 1
- },
- {
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Administrator",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "module",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
- }
\ No newline at end of file
+ "allow_rename": 1,
+ "autoname": "Prompt",
+ "creation": "2013-02-18 13:36:19",
+ "description": "DocType is a Table / Form in the application.",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "sb0",
+ "module",
+ "is_submittable",
+ "istable",
+ "issingle",
+ "editable_grid",
+ "quick_entry",
+ "cb01",
+ "track_changes",
+ "track_seen",
+ "track_views",
+ "custom",
+ "beta",
+ "fields_section_break",
+ "fields",
+ "sb1",
+ "autoname",
+ "name_case",
+ "column_break_15",
+ "description",
+ "form_settings_section",
+ "image_field",
+ "timeline_field",
+ "max_attachments",
+ "column_break_23",
+ "hide_toolbar",
+ "allow_copy",
+ "allow_rename",
+ "allow_import",
+ "allow_events_in_timeline",
+ "view_settings",
+ "title_field",
+ "search_fields",
+ "default_print_format",
+ "sort_field",
+ "sort_order",
+ "column_break_29",
+ "document_type",
+ "icon",
+ "color",
+ "show_preview_popup",
+ "show_name_in_global_search",
+ "sb2",
+ "permissions",
+ "restrict_to_domain",
+ "read_only",
+ "in_create",
+ "web_view",
+ "has_web_view",
+ "allow_guest_to_view",
+ "route",
+ "is_published_field",
+ "advanced",
+ "engine"
+ ],
+ "fields": [
+ {
+ "fieldname": "sb0",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break"
+ },
+ {
+ "fieldname": "module",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Module",
+ "oldfieldname": "module",
+ "oldfieldtype": "Link",
+ "options": "Module Def",
+ "reqd": 1,
+ "search_index": 1
+ },
+ {
+ "depends_on": "eval:!doc.istable",
+ "description": "Once submitted, submittable documents cannot be changed. They can only be Cancelled and Amended.",
+ "fieldname": "is_submittable",
+ "fieldtype": "Check",
+ "label": "Is Submittable"
+ },
+ {
+ "description": "Child Tables are shown as a Grid in other DocTypes",
+ "fieldname": "istable",
+ "fieldtype": "Check",
+ "in_standard_filter": 1,
+ "label": "Is Child Table",
+ "oldfieldname": "istable",
+ "oldfieldtype": "Check"
+ },
+ {
+ "depends_on": "eval:!doc.istable",
+ "description": "Single Types have only one record no tables associated. Values are stored in tabSingles",
+ "fieldname": "issingle",
+ "fieldtype": "Check",
+ "in_standard_filter": 1,
+ "label": "Is Single",
+ "oldfieldname": "issingle",
+ "oldfieldtype": "Check",
+ "set_only_once": 1
+ },
+ {
+ "default": "1",
+ "depends_on": "istable",
+ "fieldname": "editable_grid",
+ "fieldtype": "Check",
+ "label": "Editable Grid"
+ },
+ {
+ "default": "1",
+ "depends_on": "eval:!doc.istable && !doc.issingle",
+ "description": "Open a dialog with mandatory fields to create a new record quickly",
+ "fieldname": "quick_entry",
+ "fieldtype": "Check",
+ "label": "Quick Entry"
+ },
+ {
+ "fieldname": "cb01",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "1",
+ "depends_on": "eval:!doc.istable",
+ "description": "If enabled, changes to the document are tracked and shown in timeline",
+ "fieldname": "track_changes",
+ "fieldtype": "Check",
+ "label": "Track Changes"
+ },
+ {
+ "depends_on": "eval:!doc.istable",
+ "description": "If enabled, the document is marked as seen, the first time a user opens it",
+ "fieldname": "track_seen",
+ "fieldtype": "Check",
+ "label": "Track Seen"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:!doc.istable",
+ "description": "If enabled, document views are tracked, this can happen multiple times",
+ "fieldname": "track_views",
+ "fieldtype": "Check",
+ "label": "Track Views"
+ },
+ {
+ "fieldname": "custom",
+ "fieldtype": "Check",
+ "label": "Custom?"
+ },
+ {
+ "fieldname": "beta",
+ "fieldtype": "Check",
+ "label": "Beta"
+ },
+ {
+ "fieldname": "fields_section_break",
+ "fieldtype": "Section Break",
+ "label": "Fields",
+ "oldfieldtype": "Section Break"
+ },
+ {
+ "fieldname": "fields",
+ "fieldtype": "Table",
+ "label": "Fields",
+ "oldfieldname": "fields",
+ "oldfieldtype": "Table",
+ "options": "DocField"
+ },
+ {
+ "fieldname": "sb1",
+ "fieldtype": "Section Break",
+ "label": "Naming"
+ },
+ {
+ "description": "Naming Options:\nfield:[fieldname] - By Fieldnaming_series: - By Naming Series (field called naming_series must be presentPrompt - Prompt user for a name[series] - Series by prefix (separated by a dot); for example PRE.##### \nformat:EXAMPLE-{MM}morewords{fieldname1}-{fieldname2}-{#####} - Replace all braced words (fieldnames, date words (DD, MM, YY), series) with their value. Outside braces, any characters can be used. ",
+ "fieldname": "autoname",
+ "fieldtype": "Data",
+ "label": "Auto Name",
+ "oldfieldname": "autoname",
+ "oldfieldtype": "Data"
+ },
+ {
+ "fieldname": "name_case",
+ "fieldtype": "Select",
+ "label": "Name Case",
+ "oldfieldname": "name_case",
+ "oldfieldtype": "Select",
+ "options": "\nTitle Case\nUPPER CASE"
+ },
+ {
+ "fieldname": "column_break_15",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Text"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "form_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Form Settings"
+ },
+ {
+ "description": "Must be of type \"Attach Image\"",
+ "fieldname": "image_field",
+ "fieldtype": "Data",
+ "label": "Image Field"
+ },
+ {
+ "depends_on": "eval:!doc.istable",
+ "description": "Comments and Communications will be associated with this linked document",
+ "fieldname": "timeline_field",
+ "fieldtype": "Data",
+ "label": "Timeline Field"
+ },
+ {
+ "fieldname": "max_attachments",
+ "fieldtype": "Int",
+ "label": "Max Attachments",
+ "oldfieldname": "max_attachments",
+ "oldfieldtype": "Int"
+ },
+ {
+ "fieldname": "column_break_23",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "hide_toolbar",
+ "fieldtype": "Check",
+ "label": "Hide Sidebar and Menu",
+ "oldfieldname": "hide_toolbar",
+ "oldfieldtype": "Check"
+ },
+ {
+ "fieldname": "allow_copy",
+ "fieldtype": "Check",
+ "label": "Hide Copy",
+ "oldfieldname": "allow_copy",
+ "oldfieldtype": "Check"
+ },
+ {
+ "fieldname": "allow_rename",
+ "fieldtype": "Check",
+ "label": "Allow Rename",
+ "oldfieldname": "allow_rename",
+ "oldfieldtype": "Check"
+ },
+ {
+ "fieldname": "allow_import",
+ "fieldtype": "Check",
+ "label": "Allow Import (via Data Import Tool)"
+ },
+ {
+ "fieldname": "allow_events_in_timeline",
+ "fieldtype": "Check",
+ "label": "Allow events in timeline"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "view_settings",
+ "fieldtype": "Section Break",
+ "label": "View Settings"
+ },
+ {
+ "depends_on": "eval:!doc.istable",
+ "fieldname": "title_field",
+ "fieldtype": "Data",
+ "label": "Title Field"
+ },
+ {
+ "depends_on": "eval:!doc.istable",
+ "fieldname": "search_fields",
+ "fieldtype": "Data",
+ "label": "Search Fields",
+ "oldfieldname": "search_fields",
+ "oldfieldtype": "Data"
+ },
+ {
+ "fieldname": "default_print_format",
+ "fieldtype": "Data",
+ "label": "Default Print Format"
+ },
+ {
+ "default": "modified",
+ "depends_on": "eval:!doc.istable",
+ "fieldname": "sort_field",
+ "fieldtype": "Data",
+ "label": "Default Sort Field"
+ },
+ {
+ "default": "DESC",
+ "depends_on": "eval:!doc.istable",
+ "fieldname": "sort_order",
+ "fieldtype": "Select",
+ "label": "Default Sort Order",
+ "options": "ASC\nDESC"
+ },
+ {
+ "fieldname": "column_break_29",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "document_type",
+ "fieldtype": "Select",
+ "label": "Show in Module Section",
+ "oldfieldname": "document_type",
+ "oldfieldtype": "Select",
+ "options": "\nDocument\nSetup\nSystem\nOther"
+ },
+ {
+ "fieldname": "icon",
+ "fieldtype": "Data",
+ "label": "Icon"
+ },
+ {
+ "fieldname": "color",
+ "fieldtype": "Data",
+ "label": "Color"
+ },
+ {
+ "fieldname": "show_name_in_global_search",
+ "fieldtype": "Check",
+ "label": "Make \"name\" searchable in Global Search"
+ },
+ {
+ "depends_on": "eval:!doc.istable",
+ "fieldname": "sb2",
+ "fieldtype": "Section Break",
+ "label": "Permission Rules"
+ },
+ {
+ "fieldname": "permissions",
+ "fieldtype": "Table",
+ "label": "Permissions",
+ "oldfieldname": "permissions",
+ "oldfieldtype": "Table",
+ "options": "DocPerm"
+ },
+ {
+ "fieldname": "restrict_to_domain",
+ "fieldtype": "Link",
+ "label": "Restrict To Domain",
+ "options": "Domain"
+ },
+ {
+ "fieldname": "read_only",
+ "fieldtype": "Check",
+ "label": "User Cannot Search",
+ "oldfieldname": "read_only",
+ "oldfieldtype": "Check"
+ },
+ {
+ "fieldname": "in_create",
+ "fieldtype": "Check",
+ "label": "User Cannot Create",
+ "oldfieldname": "in_create",
+ "oldfieldtype": "Check"
+ },
+ {
+ "fieldname": "web_view",
+ "fieldtype": "Section Break",
+ "label": "Web View"
+ },
+ {
+ "default": "0",
+ "fieldname": "has_web_view",
+ "fieldtype": "Check",
+ "label": "Has Web View"
+ },
+ {
+ "default": "0",
+ "depends_on": "has_web_view",
+ "fieldname": "allow_guest_to_view",
+ "fieldtype": "Check",
+ "label": "Allow Guest to View"
+ },
+ {
+ "depends_on": "has_web_view",
+ "fieldname": "route",
+ "fieldtype": "Data",
+ "label": "Route"
+ },
+ {
+ "depends_on": "has_web_view",
+ "fieldname": "is_published_field",
+ "fieldtype": "Data",
+ "label": "Is Published Field"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "advanced",
+ "fieldtype": "Section Break",
+ "hidden": 1,
+ "label": "Advanced"
+ },
+ {
+ "default": "InnoDB",
+ "depends_on": "eval:!doc.issingle",
+ "fieldname": "engine",
+ "fieldtype": "Select",
+ "label": "Database Engine",
+ "options": "InnoDB\nMyISAM"
+ },
+ {
+ "default": "0",
+ "fieldname": "show_preview_popup",
+ "fieldtype": "Check",
+ "label": "Show Preview Popup"
+ }
+ ],
+ "icon": "fa fa-bolt",
+ "idx": 6,
+ "modified": "2019-05-16 14:58:33.405381",
+ "modified_by": "Administrator",
+ "module": "Core",
+ "name": "DocType",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Administrator",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "search_fields": "module",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py
index 484f12811c..7efdba3237 100644
--- a/frappe/core/doctype/doctype/doctype.py
+++ b/frappe/core/doctype/doctype/doctype.py
@@ -17,7 +17,10 @@ from frappe.desk.notifications import delete_notification_count_for
from frappe.modules import make_boilerplate, get_doc_path
from frappe.database.schema import validate_column_name, validate_column_length
from frappe.model.docfield import supports_translation
+from frappe.modules.import_file import get_file_path
+from six import iteritems
import frappe.website.render
+import json
class InvalidFieldNameError(frappe.ValidationError): pass
@@ -252,7 +255,8 @@ class DocType(Document):
self.update_fields_to_fetch()
from frappe import conf
- if not self.custom and not (frappe.flags.in_import or frappe.flags.in_test) and conf.get('developer_mode'):
+ allow_doctype_export = frappe.flags.allow_doctype_export or (not frappe.flags.in_test and conf.get('developer_mode'))
+ if not self.custom and not frappe.flags.in_import and allow_doctype_export:
self.export_doc()
self.make_controller_template()
@@ -343,7 +347,8 @@ class DocType(Document):
if merge:
frappe.throw(_("DocType can not be merged"))
- if not frappe.flags.in_test and not frappe.flags.in_patch:
+ # Do not rename and move files and folders for custom doctype
+ if not self.custom and not frappe.flags.in_test and not frappe.flags.in_patch:
self.rename_files_and_folders(old, new)
def after_rename(self, old, new, merge=False):
@@ -403,6 +408,72 @@ class DocType(Document):
if naming_series[0].default:
make_property_setter(self.name, "naming_series", "default", naming_series[0].default, "Text", validate_fields_for_doctype=False)
+ def before_export(self, docdict):
+ # remove null and empty fields
+ def remove_null_fields(o):
+ to_remove = []
+ for attr, value in iteritems(o):
+ if isinstance(value, list):
+ for v in value:
+ remove_null_fields(v)
+ elif not value:
+ to_remove.append(attr)
+
+ for attr in to_remove:
+ del o[attr]
+
+ remove_null_fields(docdict)
+
+ # retain order of 'fields' table and change order in 'field_order'
+ docdict["field_order"] = [f.fieldname for f in self.fields]
+
+ path = get_file_path(self.module, "DocType", self.name)
+ if os.path.exists(path):
+ try:
+ with open(path, 'r') as txtfile:
+ olddoc = json.loads(txtfile.read())
+
+ old_field_names = [f['fieldname'] for f in olddoc.get("fields", [])]
+ if old_field_names:
+ new_field_dicts = []
+ remaining_field_names = [f.fieldname for f in self.fields]
+
+ for fieldname in old_field_names:
+ field_dict = list(filter(lambda d: d['fieldname'] == fieldname, docdict['fields']))
+ if field_dict:
+ new_field_dicts.append(field_dict[0])
+ remaining_field_names.remove(fieldname)
+
+ for fieldname in remaining_field_names:
+ field_dict = list(filter(lambda d: d['fieldname'] == fieldname, docdict['fields']))
+ new_field_dicts.append(field_dict[0])
+
+ docdict['fields'] = new_field_dicts
+ except ValueError:
+ pass
+
+ @staticmethod
+ def prepare_for_import(docdict):
+ # set order of fields from field_order
+ if docdict.get("field_order"):
+ new_field_dicts = []
+ remaining_field_names = [f['fieldname'] for f in docdict.get('fields', [])]
+
+ for fieldname in docdict.get('field_order'):
+ field_dict = list(filter(lambda d: d['fieldname'] == fieldname, docdict.get('fields', [])))
+ if field_dict:
+ new_field_dicts.append(field_dict[0])
+ remaining_field_names.remove(fieldname)
+
+ for fieldname in remaining_field_names:
+ field_dict = list(filter(lambda d: d['fieldname'] == fieldname, docdict.get('fields', [])))
+ new_field_dicts.append(field_dict[0])
+
+ docdict['fields'] = new_field_dicts
+
+ if "field_order" in docdict:
+ del docdict["field_order"]
+
def export_doc(self):
"""Export to standard folder `[module]/doctype/[name]/[name].json`."""
from frappe.modules.export_file import export_to_files
@@ -545,7 +616,9 @@ def validate_fields(meta):
frappe.throw(_("Options 'Dynamic Link' type of field must point to another Link Field with options as 'DocType'"))
def check_illegal_default(d):
- if d.fieldtype == "Check" and d.default and d.default not in ('0', '1'):
+ if d.fieldtype == "Check" and not d.default:
+ d.default = '0'
+ if d.fieldtype == "Check" and d.default not in ('0', '1'):
frappe.throw(_("Default for 'Check' type of field must be either '0' or '1'"))
if d.fieldtype == "Select" and d.default and (d.default not in d.options.split("\n")):
frappe.throw(_("Default for {0} must be an option").format(d.fieldname))
diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py
index 41a4267c97..4a0782340d 100644
--- a/frappe/core/doctype/doctype/test_doctype.py
+++ b/frappe/core/doctype/doctype/test_doctype.py
@@ -104,4 +104,125 @@ class TestDocType(unittest.TestCase):
for depends_on in ["depends_on", "collapsible_depends_on"]:
condition = field.get(depends_on)
if condition:
- self.assertFalse(re.match(pattern, condition))
\ No newline at end of file
+ self.assertFalse(re.match(pattern, condition))
+
+ def test_sync_field_order(self):
+ from frappe.modules.import_file import get_file_path
+ import os
+
+ # create test doctype
+ test_doctype = frappe.get_doc({
+ "doctype": "DocType",
+ "module": "Core",
+ "fields": [
+ {
+ "label": "Field 1",
+ "fieldname": "field_1",
+ "fieldtype": "Data"
+ },
+ {
+ "label": "Field 2",
+ "fieldname": "field_2",
+ "fieldtype": "Data"
+ },
+ {
+ "label": "Field 3",
+ "fieldname": "field_3",
+ "fieldtype": "Data"
+ },
+ {
+ "label": "Field 4",
+ "fieldname": "field_4",
+ "fieldtype": "Data"
+ }
+ ],
+ "permissions": [{
+ "role": "System Manager",
+ "read": 1
+ }],
+ "name": "Test Field Order DocType",
+ "__islocal": 1
+ })
+
+ path = get_file_path(test_doctype.module, test_doctype.doctype, test_doctype.name)
+ initial_fields_order = ['field_1', 'field_2', 'field_3', 'field_4']
+
+ frappe.delete_doc_if_exists("DocType", "Test Field Order DocType")
+ if os.path.isfile(path):
+ os.remove(path)
+
+ try:
+ frappe.flags.allow_doctype_export = 1
+ test_doctype.save()
+
+ # assert that field_order list is being created with the default order
+ test_doctype_json = frappe.get_file_json(path)
+ self.assertTrue(test_doctype_json.get("field_order"))
+ self.assertEqual(len(test_doctype_json['fields']), len(test_doctype_json['field_order']))
+ self.assertListEqual([f['fieldname'] for f in test_doctype_json['fields']], test_doctype_json['field_order'])
+ self.assertListEqual([f['fieldname'] for f in test_doctype_json['fields']], initial_fields_order)
+ self.assertListEqual(test_doctype_json['field_order'], initial_fields_order)
+
+ # remove field_order to test reload_doc/sync/migrate is backwards compatible without field_order
+ del test_doctype_json['field_order']
+ with open(path, 'w+') as txtfile:
+ txtfile.write(frappe.as_json(test_doctype_json))
+
+ # assert that field_order is actually removed from the json file
+ test_doctype_json = frappe.get_file_json(path)
+ self.assertFalse(test_doctype_json.get("field_order"))
+
+ # make sure that migrate/sync is backwards compatible without field_order
+ frappe.reload_doctype(test_doctype.name, force=True)
+ test_doctype.reload()
+
+ # assert that field_order list is being created with the default order again
+ test_doctype.save()
+ test_doctype_json = frappe.get_file_json(path)
+ self.assertTrue(test_doctype_json.get("field_order"))
+ self.assertEqual(len(test_doctype_json['fields']), len(test_doctype_json['field_order']))
+ self.assertListEqual([f['fieldname'] for f in test_doctype_json['fields']], test_doctype_json['field_order'])
+ self.assertListEqual([f['fieldname'] for f in test_doctype_json['fields']], initial_fields_order)
+ self.assertListEqual(test_doctype_json['field_order'], initial_fields_order)
+
+ # reorder fields: swap row 1 and 3
+ test_doctype.fields[0], test_doctype.fields[2] = test_doctype.fields[2], test_doctype.fields[0]
+ for i, f in enumerate(test_doctype.fields):
+ f.idx = i + 1
+
+ # assert that reordering fields only affects `field_order` rather than `fields` attr
+ test_doctype.save()
+ test_doctype_json = frappe.get_file_json(path)
+ self.assertListEqual([f['fieldname'] for f in test_doctype_json['fields']], initial_fields_order)
+ self.assertListEqual(test_doctype_json['field_order'], ['field_3', 'field_2', 'field_1', 'field_4'])
+
+ # reorder `field_order` in the json file: swap row 2 and 4
+ test_doctype_json['field_order'][1], test_doctype_json['field_order'][3] = test_doctype_json['field_order'][3], test_doctype_json['field_order'][1]
+ with open(path, 'w+') as txtfile:
+ txtfile.write(frappe.as_json(test_doctype_json))
+
+ # assert that reordering `field_order` from json file is reflected in DocType upon migrate/sync
+ frappe.reload_doctype(test_doctype.name, force=True)
+ test_doctype.reload()
+ self.assertListEqual([f.fieldname for f in test_doctype.fields], ['field_3', 'field_4', 'field_1', 'field_2'])
+
+ # insert row in the middle and remove first row (field 3)
+ test_doctype.append("fields", {
+ "label": "Field 5",
+ "fieldname": "field_5",
+ "fieldtype": "Data"
+ })
+ test_doctype.fields[4], test_doctype.fields[3] = test_doctype.fields[3], test_doctype.fields[4]
+ test_doctype.fields[3], test_doctype.fields[2] = test_doctype.fields[2], test_doctype.fields[3]
+ test_doctype.remove(test_doctype.fields[0])
+ for i, f in enumerate(test_doctype.fields):
+ f.idx = i + 1
+
+ test_doctype.save()
+ test_doctype_json = frappe.get_file_json(path)
+ self.assertListEqual([f['fieldname'] for f in test_doctype_json['fields']], ['field_1', 'field_2', 'field_4', 'field_5'])
+ self.assertListEqual(test_doctype_json['field_order'], ['field_4', 'field_5', 'field_1', 'field_2'])
+ except:
+ raise
+ finally:
+ frappe.flags.allow_doctype_export = 0
diff --git a/frappe/core/doctype/dynamic_link/dynamic_link.json b/frappe/core/doctype/dynamic_link/dynamic_link.json
index 3689be6a3d..abc47df100 100644
--- a/frappe/core/doctype/dynamic_link/dynamic_link.json
+++ b/frappe/core/doctype/dynamic_link/dynamic_link.json
@@ -1,125 +1,47 @@
{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-01-13 04:55:18.835023",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "creation": "2017-01-13 04:55:18.835023",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "link_doctype",
+ "link_name",
+ "link_title"
+ ],
"fields": [
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "link_doctype",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Link DocType",
- "length": 0,
- "no_copy": 0,
- "options": "DocType",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "link_doctype",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Link DocType",
+ "options": "DocType",
+ "reqd": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "link_name",
- "fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Link Name",
- "length": 0,
- "no_copy": 0,
- "options": "link_doctype",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "link_name",
+ "fieldtype": "Dynamic Link",
+ "in_list_view": 1,
+ "label": "Link Name",
+ "options": "link_doctype",
+ "reqd": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "link_title",
- "fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Link Title",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "fieldname": "link_title",
+ "fieldtype": "Read Only",
+ "in_list_view": 1,
+ "label": "Link Title",
+ "read_only": 1
}
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
-
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2017-01-17 14:25:49.140730",
- "modified_by": "Administrator",
- "module": "Core",
- "name": "Dynamic Link",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
+ ],
+ "istable": 1,
+ "modified": "2019-05-16 19:54:31.400026",
+ "modified_by": "Administrator",
+ "module": "Core",
+ "name": "Dynamic Link",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/frappe/core/doctype/feedback_request/feedback_request.js b/frappe/core/doctype/feedback_request/feedback_request.js
deleted file mode 100644
index d32982a9f1..0000000000
--- a/frappe/core/doctype/feedback_request/feedback_request.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2016, Frappe Technologies and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Feedback Request', {
- refresh: function(frm) {
- var rating_icons = frappe.render_template("rating_icons", {rating: frm.doc.rating, show_label: false});
- $(frm.fields_dict.feedback_rating.wrapper).html(rating_icons);
-
- if(frm.doc.reference_doctype && frm.doc.reference_name) {
- frm.add_custom_button(__(frm.doc.reference_name), function() {
- frappe.set_route("Form", frm.doc.reference_doctype, frm.doc.reference_name);
- });
- }
-
- if(frm.doc.reference_communication){
- frm.add_custom_button(__("Communication"), function() {
- frappe.set_route("Form", "Communication", frm.doc.reference_communication);
- });
- }
- }
-});
diff --git a/frappe/core/doctype/feedback_request/feedback_request.json b/frappe/core/doctype/feedback_request/feedback_request.json
deleted file mode 100644
index 6cbc27ac26..0000000000
--- a/frappe/core/doctype/feedback_request/feedback_request.json
+++ /dev/null
@@ -1,470 +0,0 @@
-{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "",
- "beta": 0,
- "creation": "2017-01-27 15:43:33.780808",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 1,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "is_sent",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Sent",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "is_feedback_submitted",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Feedback Submitted",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Is Feedback request triggered manually ?",
- "fieldname": "is_manual",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Manual",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 1,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "key",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Key",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reference",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Reference",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "reference_doctype",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Reference DocType",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "reference_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Reference Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_5",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "feedback_trigger",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Feedback Trigger",
- "length": 0,
- "no_copy": 0,
- "options": "Feedback Trigger",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "collapsible_depends_on": "eval: doc.rating",
- "columns": 0,
- "fieldname": "section_break_1",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Feedback Rating",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "rating",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Rating",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "feedback_rating",
- "fieldtype": "HTML",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Feedback Rating",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reference_communication",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Reference Communication",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 1,
-
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-03-03 08:11:09.718589",
- "modified_by": "Administrator",
- "module": "Core",
- "name": "Feedback Request",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 0
- }
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "reference_name",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/frappe/core/doctype/feedback_request/feedback_request.py b/frappe/core/doctype/feedback_request/feedback_request.py
deleted file mode 100644
index 8605d10f8a..0000000000
--- a/frappe/core/doctype/feedback_request/feedback_request.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, Frappe Technologies and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-from frappe.utils import get_datetime
-
-class FeedbackRequest(Document):
- def autoname(self):
- """ feedback request name in the format Feedback for {doctype} {name} on {datetime}"""
-
- self.name = "Feedback for {doctype} {docname} on {datetime}".format(
- doctype=self.reference_doctype,
- docname=self.reference_name,
- datetime=get_datetime()
- )
-
- def before_insert(self):
- from frappe.utils import random_string
-
- self.key = random_string(32)
-
-@frappe.whitelist(allow_guest=True)
-def is_valid_feedback_request(key=None):
- if not key:
- return False
-
- is_feedback_submitted = frappe.db.get_value("Feedback Request", { "key": key }, "is_feedback_submitted")
- if is_feedback_submitted:
- return False
- else:
- return True
-
-def delete_feedback_request():
- """ clear 100 days old feedback request """
- frappe.db.sql("""delete from `tabFeedback Request` where `creation` < (NOW() - INTERVAL '100' DAY)""")
\ No newline at end of file
diff --git a/frappe/core/doctype/feedback_request/feedback_request_list.js b/frappe/core/doctype/feedback_request/feedback_request_list.js
deleted file mode 100644
index 69d511582f..0000000000
--- a/frappe/core/doctype/feedback_request/feedback_request_list.js
+++ /dev/null
@@ -1,16 +0,0 @@
-frappe.listview_settings['Feedback Request'] = {
- colwidths: {
- subject: 2,
- },
- column_render: {
- rating: function(doc) {
- var html = ""
- for (var i = 0; i < 5; i++) {
- html += repl(" ",
- {color: i{{ doc.name }} Delivered ",
- "fieldname": "subject",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Subject",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "description": "Send Feedback Request only if there is at least one communication is available for the document.",
- "fieldname": "check_communication",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Check Communication",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Optional: The alert will be sent if this expression is true",
- "fieldname": "condition",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Condition",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_7",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "html_8",
- "fieldtype": "HTML",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "options": "Condition Examples:
\ndoc.status==\"Closed\"\ndoc.due_date==nowdate()\ndoc.total > 40000\n ",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_9",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Message",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "message",
- "fieldtype": "Code",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Message",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "example",
- "fieldtype": "HTML",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Example",
- "length": 0,
- "no_copy": 0,
- "options": "Message Example \n\n<h3>Issue Resolved</h3>\n\n<p>Issue {{ doc.name }} Is resolved. Please check and confirm the same.</p>\n\n<p> Your Feedback is important for us. Please give us your Feedback for {{ doc.name }}</p>\n\n<h4>Details</h4> ",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-05-29 16:36:04.178592",
- "modified_by": "Administrator",
- "module": "Core",
- "name": "Feedback Trigger",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "document_type",
- "track_changes": 1,
- "track_seen": 0
-}
diff --git a/frappe/core/doctype/feedback_trigger/feedback_trigger.py b/frappe/core/doctype/feedback_trigger/feedback_trigger.py
deleted file mode 100644
index e2265913ad..0000000000
--- a/frappe/core/doctype/feedback_trigger/feedback_trigger.py
+++ /dev/null
@@ -1,215 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, Frappe Technologies and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import json
-import frappe
-from frappe import _
-from frappe.utils import get_url
-from frappe.model.document import Document
-from frappe.utils.jinja import validate_template
-
-class FeedbackTrigger(Document):
- def validate(self):
- frappe.cache().delete_value('feedback_triggers')
- validate_template(self.subject)
- validate_template(self.message)
- self.validate_condition()
-
- def on_trash(self):
- frappe.cache().delete_value('feedback_triggers')
-
- def validate_condition(self):
- temp_doc = frappe.new_doc(self.document_type)
- if self.condition:
- try:
- frappe.safe_eval(self.condition, None, get_context(temp_doc))
- except:
- frappe.throw(_("The condition '{0}' is invalid").format(self.condition))
-
-def trigger_feedback_request(doc, method):
- """Trigger the feedback alert, or delete feedback requests on delete"""
-
- def _get():
- triggers = {}
- if not (frappe.flags.in_migrate or frappe.flags.in_install):
- for d in frappe.get_all('Feedback Trigger', dict(enabled=1), ['name', 'document_type']):
- triggers[d.document_type] = d.name
-
- return triggers
-
- feedback_triggers = frappe.cache().get_value('feedback_triggers', _get)
- if doc.doctype in feedback_triggers:
- if doc.flags.in_delete:
- frappe.enqueue('frappe.core.doctype.feedback_trigger.feedback_trigger.delete_feedback_request_and_feedback',
- reference_doctype=doc.doctype, reference_name=doc.name, now=frappe.flags.in_test)
- else:
- frappe.enqueue('frappe.core.doctype.feedback_trigger.feedback_trigger.send_feedback_request',
- trigger=feedback_triggers[doc.doctype], reference_doctype=doc.doctype,
- reference_name=doc.name, now=frappe.flags.in_test)
-
-@frappe.whitelist()
-def send_feedback_request(reference_doctype, reference_name, trigger="Manual", details=None, is_manual=False):
- """ send feedback alert """
-
- if is_feedback_request_already_sent(reference_doctype, reference_name, is_manual=is_manual):
- frappe.msgprint(_("Feedback Request is already sent to user"))
- return None
-
- details = json.loads(details) if details else \
- get_feedback_request_details(reference_doctype, reference_name, trigger=trigger)
-
- if not details:
- return None
-
- feedback_request, url = get_feedback_request_url(reference_doctype,
- reference_name, details.get("recipients"), trigger)
-
- feedback_msg = frappe.render_template("templates/emails/feedback_request_url.html", { "url": url })
-
- # appending feedback url to message body
- message = "{message}{feedback_msg}".format(
- message=details.get("message"),
- feedback_msg=feedback_msg
- )
- details.update({
- "message": message,
- "header": [details.get('subject'), 'blue']
- })
-
- if details:
- frappe.sendmail(**details)
- frappe.db.set_value("Feedback Request", feedback_request, "is_sent", 1)
-
-
-@frappe.whitelist()
-def get_feedback_request_details(reference_doctype, reference_name, trigger="Manual", request=None):
- if not frappe.db.get_value(reference_doctype, reference_name):
- # reference document is either deleted or renamed
- return
- elif not trigger and not request and not frappe.db.get_value("Feedback Trigger", { "document_type": reference_doctype }):
- return
- elif not trigger and request:
- trigger = frappe.db.get_value("Feedback Request", request, "feedback_trigger")
- else:
- trigger = frappe.db.get_value("Feedback Trigger", { "document_type": reference_doctype })
-
- if not trigger:
- return
-
- feedback_trigger = frappe.get_doc("Feedback Trigger", trigger)
-
- doc = frappe.get_doc(reference_doctype, reference_name)
- context = get_context(doc)
-
- recipients = doc.get(feedback_trigger.email_fieldname, None)
- if feedback_trigger.check_communication:
- communications = frappe.get_all("Communication", filters={
- "reference_doctype": reference_doctype,
- "reference_name": reference_name,
- "communication_type": "Communication",
- "sent_or_received": "Sent"
- }, fields=["name"])
-
- if len(communications) < 1:
- frappe.msgprint(_("At least one reply is mandatory before requesting feedback"))
- return None
-
- if recipients and (not feedback_trigger.condition or \
- frappe.safe_eval(feedback_trigger.condition, None, context)):
- subject = feedback_trigger.subject
- context.update({ "feedback_trigger": feedback_trigger })
-
- if "{" in subject:
- subject = frappe.render_template(feedback_trigger.subject, context)
-
- feedback_request_message = frappe.render_template(feedback_trigger.message, context)
-
- return {
- "subject": subject,
- "recipients": recipients,
- "reference_name":doc.name,
- "reference_doctype":doc.doctype,
- "message": feedback_request_message,
- }
- else:
- frappe.msgprint(_("Feedback conditions do not match"))
- return None
-
-def get_feedback_request_url(reference_doctype, reference_name, recipients, trigger="Manual"):
- """ prepare the feedback request url """
- is_manual = 1 if trigger == "Manual" else 0
- feedback_request = frappe.get_doc({
- "is_manual": is_manual,
- "feedback_trigger": trigger,
- "doctype": "Feedback Request",
- "reference_name": reference_name,
- "reference_doctype": reference_doctype,
- }).insert(ignore_permissions=True)
-
- feedback_url = "{base_url}/feedback?reference_doctype={doctype}&reference_name={docname}&email={email_id}&key={nonce}".format(
- base_url=get_url(),
- doctype=reference_doctype,
- docname=reference_name,
- email_id=recipients,
- nonce=feedback_request.key
- )
-
- return [ feedback_request.name, feedback_url ]
-
-def is_feedback_request_already_sent(reference_doctype, reference_name, is_manual=False):
- """
- check if feedback request mail is already sent but feedback is not submitted
- to avoid sending multiple feedback request mail
- """
- is_request_sent = False
- filters = {
- "is_sent": 1,
- "reference_name": reference_name,
- "is_manual": 1 if is_manual else 0,
- "reference_doctype": reference_doctype
- }
-
- if is_manual:
- filters.update({ "is_feedback_submitted": 0 })
-
- feedback_request = frappe.get_all("Feedback Request", filters=filters, fields=["name"])
-
- if feedback_request: is_request_sent = True
- return is_request_sent
-
-def get_enabled_feedback_trigger():
- """ get mapper of all the enable feedback trigger """
-
- triggers = frappe.get_all("Feedback Trigger", filters={"enabled": 1},
- fields=["document_type", "name"], as_list=True)
-
- triggers = { dt[0]: dt[1] for dt in triggers }
- return triggers
-
-def get_context(doc):
- return { "doc": doc }
-
-def delete_feedback_request_and_feedback(reference_doctype, reference_name):
- """ delete all the feedback request and feedback communication """
- if not all([reference_doctype, reference_name]):
- return
-
- feedback_requests = frappe.get_all("Feedback Request", filters={
- "is_feedback_submitted": 0,
- "reference_doctype": reference_doctype,
- "reference_name": reference_name
- })
-
- communications = frappe.get_all("Communication", {
- "communication_type": "Feedback",
- "reference_doctype": reference_doctype,
- "reference_name": reference_name
- })
-
- for request in feedback_requests:
- frappe.delete_doc("Feedback Request", request.get("name"), ignore_permissions=True)
-
- for communication in communications:
- frappe.delete_doc("Communication", communication.get("name"), ignore_permissions=True)
diff --git a/frappe/core/doctype/feedback_trigger/test_feedback_trigger.py b/frappe/core/doctype/feedback_trigger/test_feedback_trigger.py
deleted file mode 100644
index f44d1f96ae..0000000000
--- a/frappe/core/doctype/feedback_trigger/test_feedback_trigger.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, Frappe Technologies and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-# test_records = frappe.get_test_records('Feedback Trigger')
-def get_feedback_request(todo, feedback_trigger):
- return frappe.db.get_value("Feedback Request", {
- "is_sent": 1,
- "is_feedback_submitted": 0,
- "reference_doctype": "ToDo",
- "reference_name": todo,
- "feedback_trigger": feedback_trigger
- }, ["name", "key"])
-
-class TestFeedbackTrigger(unittest.TestCase):
- def setUp(self):
- new_user = frappe.get_doc(dict(doctype='User', email='test-feedback@example.com',
- first_name='Tester')).insert(ignore_permissions=True)
- new_user.add_roles("System Manager")
-
- def tearDown(self):
- frappe.db.sql("delete from tabContact where email_id='test-feedback@example.com'")
- frappe.delete_doc("User", "test-feedback@example.com")
- frappe.delete_doc("Feedback Trigger", "ToDo")
- frappe.db.sql('delete from `tabEmail Queue`')
- frappe.db.sql('delete from `tabFeedback Request`')
-
- def test_feedback_trigger(self):
- """ Test feedback trigger """
- from frappe.www.feedback import accept
-
- frappe.delete_doc("Feedback Trigger", "ToDo")
- frappe.db.sql('delete from `tabEmail Queue`')
- frappe.db.sql('delete from `tabFeedback Request`')
-
- feedback_trigger = frappe.get_doc({
- "enabled": 1,
- "doctype": "Feedback Trigger",
- "document_type": "ToDo",
- "email_field": "assigned_by",
- "email_fieldname": "assigned_by",
- "subject": "{{ doc.name }} Task Completed",
- "condition": "doc.status == 'Closed'",
- "message": """Task {{ doc.name }} is Completed by {{ doc.owner }}.
- regarding the Task {{ doc.name }}"""
- }).insert(ignore_permissions=True)
-
- # create a todo
- todo = frappe.get_doc({
- "doctype": "ToDo",
- "owner": "test-feedback@example.com",
- "assigned_by": "test-feedback@example.com",
- "description": "Unable To Submit Sales Order #SO-00001"
- }).insert(ignore_permissions=True)
-
- # feedback alert mail should be sent only on 'Closed' status
- email_queue = frappe.db.sql("""select name from `tabEmail Queue` where
- reference_doctype='ToDo' and reference_name='{0}'""".format(todo.name))
- self.assertFalse(email_queue)
-
- # add a communication
- frappe.get_doc({
- "reference_doctype": "ToDo",
- "reference_name": todo.name,
- "communication_type": "Communication",
- "content": "Test Communication",
- "subject": "Test Communication",
- "doctype": "Communication"
- }).insert(ignore_permissions=True)
-
- # check if feedback mail alert is triggered
- todo.reload()
- todo.status = "Closed"
- todo.save(ignore_permissions=True)
-
- email_queue = frappe.db.sql("""select name from `tabEmail Queue` where
- reference_doctype='ToDo' and reference_name='{0}'""".format(todo.name))
- self.assertTrue(email_queue)
-
- # test if feedback is submitted for the todo
- feedback_request, request_key = get_feedback_request(todo.name, feedback_trigger.name)
- self.assertTrue(feedback_request)
-
- # test if mail alerts are triggered multiple times for same document
- todo.save(ignore_permissions=True)
- email_queue = frappe.db.sql("""select name from `tabEmail Queue` where
- reference_doctype='ToDo' and reference_name='{0}'""".format(todo.name))
- self.assertTrue(len(email_queue) == 1)
- frappe.db.sql('delete from `tabEmail Queue`')
-
-
- # Test if feedback is submitted sucessfully
- result = accept(request_key, "test-feedback@example.com", "ToDo", todo.name, "Great Work !!", 4, fullname="Test User")
- self.assertTrue(result)
-
- # test if feedback is saved in Communication
- docname = frappe.db.get_value("Communication", {
- "reference_doctype": "ToDo",
- "reference_name": todo.name,
- "communication_type": "Feedback",
- "feedback_request": feedback_request
- })
-
- communication = frappe.get_doc("Communication", docname)
- self.assertEqual(communication.rating, 4)
- self.assertEqual(communication.content, "Great Work !!")
-
- # test if link expired after feedback submission
- self.assertRaises(Exception, accept, key=request_key, sender="test-feedback@example.com",
- reference_doctype="ToDo", reference_name=todo.name, feedback="Thank You !!", rating=4, fullname="Test User")
-
- # auto feedback request should trigger only once
- todo.reload()
- todo.save(ignore_permissions=True)
- email_queue = frappe.db.sql("""select name from `tabEmail Queue` where
- reference_doctype='ToDo' and reference_name='{0}'""".format(todo.name))
- self.assertFalse(email_queue)
- frappe.delete_doc("ToDo", todo.name)
-
- # test if feedback requests and feedback communications are deleted?
- communications = frappe.get_all("Communication", {
- "reference_doctype": "ToDo",
- "reference_name": todo.name,
- "communication_type": "Feedback"
- })
- self.assertFalse(communications)
-
- feedback_requests = frappe.get_all("Feedback Request", {
- "reference_doctype": "ToDo",
- "reference_name": todo.name,
- "is_feedback_submitted": 0
- })
- self.assertFalse(feedback_requests)
diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py
index 6942b72f6a..fff4a5e344 100755
--- a/frappe/core/doctype/file/file.py
+++ b/frappe/core/doctype/file/file.py
@@ -290,6 +290,8 @@ class File(NestedSet):
zip_path = frappe.get_site_path(self.file_url.strip('/'))
base_url = os.path.dirname(self.file_url)
+
+ files = []
with zipfile.ZipFile(zip_path) as zf:
zf.extractall(os.path.dirname(zip_path))
for info in zf.infolist():
@@ -308,8 +310,10 @@ class File(NestedSet):
file_doc.attached_to_doctype = self.attached_to_doctype
file_doc.attached_to_name = self.attached_to_name
file_doc.save()
+ files.append(file_doc)
frappe.delete_doc('File', self.name)
+ return files
def get_file_url(self):
@@ -888,7 +892,8 @@ def get_random_filename(extn=None, content_type=None):
def unzip_file(name):
'''Unzip the given file and make file records for each of the extracted files'''
file_obj = frappe.get_doc('File', name)
- file_obj.unzip()
+ files = file_obj.unzip()
+ return len(files)
@frappe.whitelist()
@@ -919,3 +924,10 @@ def validate_filename(filename):
timestamp = now_datetime().strftime(" %Y-%m-%d %H:%M:%S")
fname = get_file_name(filename, timestamp)
return fname
+
+@frappe.whitelist()
+def get_files_in_folder(folder):
+ return frappe.db.get_all('File',
+ { 'folder': folder },
+ ['name', 'file_name', 'file_url', 'is_folder', 'modified']
+ )
diff --git a/frappe/core/doctype/page/page.js b/frappe/core/doctype/page/page.js
index 86fbbedaf3..d1d9600e59 100644
--- a/frappe/core/doctype/page/page.js
+++ b/frappe/core/doctype/page/page.js
@@ -3,9 +3,14 @@
frappe.ui.form.on('Page', {
refresh: function(frm) {
- if(!frappe.boot.developer_mode && user != 'Administrator') {
+ if (!frappe.boot.developer_mode && frappe.session.user != 'Administrator') {
// make the document read-only
frm.set_read_only();
}
+ if (!frm.is_new() && !frm.doc.istable) {
+ frm.add_custom_button(__('Go to {0} Page', [frm.doc.title || frm.doc.name]), () => {
+ frappe.set_route(frm.doc.name);
+ });
+ }
}
});
diff --git a/frappe/core/doctype/prepared_report/prepared_report.json b/frappe/core/doctype/prepared_report/prepared_report.json
index e1b122e68a..ec89c6327a 100644
--- a/frappe/core/doctype/prepared_report/prepared_report.json
+++ b/frappe/core/doctype/prepared_report/prepared_report.json
@@ -21,6 +21,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "report_name",
"fieldtype": "Data",
"hidden": 1,
@@ -53,6 +54,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "ref_report_doctype",
"fieldtype": "Link",
"hidden": 1,
@@ -86,6 +88,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "default": "Queued",
+ "fetch_if_empty": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 1,
@@ -93,12 +97,12 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
"in_standard_filter": 0,
"label": "Status",
"length": 0,
"no_copy": 0,
- "options": "Queued\nCompleted",
+ "options": "Error\nQueued\nCompleted",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -119,6 +123,39 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "report_start_time",
"fieldtype": "Datetime",
"hidden": 0,
@@ -151,6 +188,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "report_end_time",
"fieldtype": "Datetime",
"hidden": 0,
@@ -183,6 +221,73 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "eval:doc.status == 'Error'",
+ "fetch_if_empty": 0,
+ "fieldname": "section_break_7",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "error_message",
+ "fieldtype": "Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Error Message",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "filters_sb",
"fieldtype": "Section Break",
"hidden": 0,
@@ -215,6 +320,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "filters",
"fieldtype": "Small Text",
"hidden": 1,
@@ -247,6 +353,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "filter_values",
"fieldtype": "HTML",
"hidden": 0,
@@ -279,6 +386,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "columns",
"fieldtype": "Code",
"hidden": 1,
@@ -315,7 +423,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-10-23 16:58:14.879417",
+ "modified": "2019-04-19 12:39:47.211516",
"modified_by": "Administrator",
"module": "Core",
"name": "Prepared Report",
diff --git a/frappe/core/doctype/prepared_report/prepared_report.py b/frappe/core/doctype/prepared_report/prepared_report.py
index 1cd106dabd..29c069515f 100644
--- a/frappe/core/doctype/prepared_report/prepared_report.py
+++ b/frappe/core/doctype/prepared_report/prepared_report.py
@@ -25,25 +25,43 @@ class PreparedReport(Document):
self.status = "Queued"
self.report_start_time = frappe.utils.now()
- def after_insert(self):
+ def enqueue_report(self):
enqueue(
run_background,
- instance=self, timeout=6000
+ prepared_report=self.name, timeout=6000
)
def on_trash(self):
remove_all("PreparedReport", self.name, from_delete=True)
-def run_background(instance):
+def run_background(prepared_report):
+ instance = frappe.get_doc("Prepared Report", prepared_report)
report = frappe.get_doc("Report", instance.ref_report_doctype)
- result = generate_report_result(report, filters=instance.filters, user=instance.owner)
- create_json_gz_file(result['result'], 'Prepared Report', instance.name)
- instance.status = "Completed"
- instance.columns = json.dumps(result["columns"])
- instance.report_end_time = frappe.utils.now()
- instance.save()
+ try:
+ report.custom_columns = []
+
+ if report.report_type == 'Custom Report':
+ custom_report_doc = report
+ reference_report = custom_report_doc.reference_report
+ report = frappe.get_doc("Report", reference_report)
+ report.custom_columns = custom_report_doc.json
+
+ result = generate_report_result(report, filters=instance.filters, user=instance.owner)
+ create_json_gz_file(result['result'], 'Prepared Report', instance.name)
+
+ instance.status = "Completed"
+ instance.columns = json.dumps(result["columns"])
+ instance.report_end_time = frappe.utils.now()
+ instance.save(ignore_permissions=True)
+
+ except Exception:
+ frappe.log_error(frappe.get_traceback())
+ instance = frappe.get_doc("Prepared Report", prepared_report)
+ instance.status = "Error"
+ instance.error_message = frappe.get_traceback()
+ instance.save(ignore_permissions=True)
frappe.publish_realtime(
'report_generated',
diff --git a/frappe/core/doctype/prepared_report/prepared_report_list.js b/frappe/core/doctype/prepared_report/prepared_report_list.js
new file mode 100644
index 0000000000..8acb3bc75a
--- /dev/null
+++ b/frappe/core/doctype/prepared_report/prepared_report_list.js
@@ -0,0 +1,12 @@
+frappe.listview_settings['Prepared Report'] = {
+ add_fields: ["status"],
+ get_indicator: function(doc) {
+ if(doc.status==="Completed"){
+ return [__("Completed"), "green", "status,=,Completed"];
+ } else if(doc.status ==="Error"){
+ return [__("Error"), "red", "status,=,Error"];
+ } else if(doc.status ==="Queued"){
+ return [__("Queued"), "orange", "status,=,Queued"];
+ }
+ }
+};
\ No newline at end of file
diff --git a/frappe/core/doctype/report/boilerplate/controller.js b/frappe/core/doctype/report/boilerplate/controller.js
index a09dff068f..5148f34462 100644
--- a/frappe/core/doctype/report/boilerplate/controller.js
+++ b/frappe/core/doctype/report/boilerplate/controller.js
@@ -6,4 +6,4 @@ frappe.query_reports["{name}"] = {{
"filters": [
]
-}}
+}};
diff --git a/frappe/core/doctype/report/boilerplate/controller.py b/frappe/core/doctype/report/boilerplate/controller.py
index 5287ecc691..55c01e4f75 100644
--- a/frappe/core/doctype/report/boilerplate/controller.py
+++ b/frappe/core/doctype/report/boilerplate/controller.py
@@ -2,7 +2,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+# import frappe
def execute(filters=None):
columns, data = [], []
diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py
index 6b40cd7d33..1b6957d057 100644
--- a/frappe/core/doctype/report/report.py
+++ b/frappe/core/doctype/report/report.py
@@ -100,7 +100,7 @@ class Report(Document):
columns = []
out = []
- if self.report_type in ('Query Report', 'Script Report'):
+ if self.report_type in ('Query Report', 'Script Report', 'Custom Report'):
# query and script reports
data = frappe.desk.query_report.run(self.name, filters=filters, user=user)
for d in data.get('columns'):
diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py
index 60a8119f10..adc054197a 100644
--- a/frappe/core/doctype/user/user.py
+++ b/frappe/core/doctype/user/user.py
@@ -12,6 +12,8 @@ from frappe.utils.user import get_system_managers
import frappe.permissions
import frappe.share
import re
+import json
+
from frappe.limits import get_limits
from frappe.website.utils import is_signup_enabled
from frappe.utils.background_jobs import enqueue
@@ -1086,4 +1088,12 @@ def generate_keys(user):
user_details.save()
return {"api_secret": api_secret}
- frappe.throw(frappe._("Not Permitted"), frappe.PermissionError)
\ No newline at end of file
+ frappe.throw(frappe._("Not Permitted"), frappe.PermissionError)
+
+@frappe.whitelist()
+def update_profile_info(profile_info):
+ profile_info = json.loads(profile_info)
+ user = frappe.get_doc('User', frappe.session.user)
+ user.update(profile_info)
+ user.save()
+ return user
\ No newline at end of file
diff --git a/frappe/core/doctype/user/user_list.js b/frappe/core/doctype/user/user_list.js
index 116e8e6d86..5632edf0cc 100644
--- a/frappe/core/doctype/user/user_list.js
+++ b/frappe/core/doctype/user/user_list.js
@@ -16,4 +16,4 @@ frappe.listview_settings['User'] = {
}
};
-frappe.help.youtube_id["User"] = "fnBoRhBrwR4";
+frappe.help.youtube_id["User"] = "8Slw1hsTmUI";
diff --git a/frappe/core/doctype/user_permission/test_user_permission.py b/frappe/core/doctype/user_permission/test_user_permission.py
index b83d103013..2fa9917daf 100644
--- a/frappe/core/doctype/user_permission/test_user_permission.py
+++ b/frappe/core/doctype/user_permission/test_user_permission.py
@@ -8,17 +8,26 @@ import frappe
import unittest
class TestUserPermission(unittest.TestCase):
+ def test_default_user_permission_validation(self):
+ user = create_user('test_default_permission@example.com')
+ param = get_params(user, 'User', user.name, is_default=1)
+ add_user_permissions(param)
+ #create a duplicate entry with default
+ perm_user = create_user('test_user_perm@example.com')
+ param = get_params(user, 'User', perm_user.name, is_default=1)
+ self.assertRaises(frappe.ValidationError, add_user_permissions, param)
+
def test_apply_to_all(self):
''' Create User permission for User having access to all applicable Doctypes'''
- user = get_user()
- param = get_params(user, apply = 1)
+ user = create_user('test_bulk_creation_update@example.com')
+ param = get_params(user, 'User', user.name)
created = add_user_permissions(param)
self.assertEquals(created, 1)
def test_for_applicable_on_update_from_apply_to_all(self):
''' Update User Permission from all to some applicable Doctypes'''
- user = get_user()
- param = get_params(user, applicable = ["Chat Room", "Chat Message"])
+ user = create_user('test_bulk_creation_update@example.com')
+ param = get_params(user, 'User', user.name , applicable = ["Chat Room", "Chat Message"])
create = add_user_permissions(param)
frappe.db.commit()
@@ -33,8 +42,8 @@ class TestUserPermission(unittest.TestCase):
def test_for_apply_to_all_on_update_from_applicable(self):
''' Update User Permission from some to all applicable Doctypes'''
- user = get_user()
- param = get_params(user, apply = 1)
+ user = create_user('test_bulk_creation_update@example.com')
+ param = get_params(user, 'User', user.name)
created = add_user_permissions(param)
created_apply_to_all = frappe.db.exists("User Permission", get_exists_param(user))
removed_applicable_first = frappe.db.exists("User Permission", get_exists_param(user, applicable = "Chat Room"))
@@ -46,26 +55,27 @@ class TestUserPermission(unittest.TestCase):
self.assertIsNone(removed_applicable_second)
self.assertEquals(created, 1)
-def get_user():
- if frappe.db.exists('User', 'test_bulk_creation_update@example.com'):
- return frappe.get_doc('User', 'test_bulk_creation_update@example.com')
+def create_user(email):
+ ''' create user with role system manager '''
+ if frappe.db.exists('User', email):
+ return frappe.get_doc('User', email)
else:
user = frappe.new_doc('User')
- user.email = 'test_bulk_creation_update@example.com'
- user.first_name = 'Test_Bulk_Creation'
+ user.email = email
+ user.first_name = email.split("@")[0]
user.add_roles("System Manager")
return user
-def get_params(user, apply = None , applicable = None):
+def get_params(user, doctype, docname, is_default=0, applicable=None):
''' Return param to insert '''
param = {
"user": user.name,
- "doctype":"User",
- "docname":user.name
+ "doctype":doctype,
+ "docname":docname,
+ "is_default": is_default,
+ "apply_to_all_doctypes": 1,
+ "applicable_doctypes": []
}
- if apply:
- param.update({"apply_to_all_doctypes": 1})
- param.update({"applicable_doctypes": []})
if applicable:
param.update({"apply_to_all_doctypes": 0})
param.update({"applicable_doctypes": applicable})
diff --git a/frappe/core/doctype/user_permission/user_permission.json b/frappe/core/doctype/user_permission/user_permission.json
index c2ea05e731..33a8d58bbb 100644
--- a/frappe/core/doctype/user_permission/user_permission.json
+++ b/frappe/core/doctype/user_permission/user_permission.json
@@ -20,6 +20,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "user",
"fieldtype": "Link",
"hidden": 0,
@@ -53,6 +54,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "allow",
"fieldtype": "Link",
"hidden": 0,
@@ -86,6 +88,39 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "for_value",
"fieldtype": "Dynamic Link",
"hidden": 0,
@@ -119,6 +154,40 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "is_default",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Is Default",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "advanced_control_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -152,6 +221,7 @@
"collapsible": 0,
"columns": 0,
"default": "1",
+ "fetch_if_empty": 0,
"fieldname": "apply_to_all_doctypes",
"fieldtype": "Check",
"hidden": 0,
@@ -185,6 +255,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:!doc.apply_to_all_doctypes",
+ "fetch_if_empty": 0,
"fieldname": "applicable_for",
"fieldtype": "Link",
"hidden": 0,
@@ -213,16 +284,14 @@
}
],
"has_web_view": 0,
- "hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
- "image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-02-13 22:58:27.428741",
+ "modified": "2019-04-16 19:17:23.644724",
"modified_by": "Administrator",
"module": "Core",
"name": "User Permission",
@@ -251,7 +320,6 @@
],
"quick_entry": 0,
"read_only": 0,
- "read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py
index 88144f8078..af2815a9ac 100644
--- a/frappe/core/doctype/user_permission/user_permission.py
+++ b/frappe/core/doctype/user_permission/user_permission.py
@@ -7,21 +7,14 @@ import frappe, json
from frappe.model.document import Document
from frappe.permissions import (get_valid_perms, update_permission_property)
from frappe import _
+from frappe.utils import cstr
from frappe.core.utils import find
from frappe.desk.form.linked_with import get_linked_doctypes
class UserPermission(Document):
def validate(self):
- duplicate_exists = frappe.db.get_all(self.doctype, filters={
- 'allow': self.allow,
- 'for_value': self.for_value,
- 'user': self.user,
- 'applicable_for': self.applicable_for,
- 'apply_to_all_doctypes': self.apply_to_all_doctypes,
- 'name': ['!=', self.name]
- }, limit=1)
- if duplicate_exists:
- frappe.throw(_("User permission already exists"), frappe.DuplicateEntryError)
+ self.validate_user_permission()
+ self.validate_default_permission()
def on_update(self):
frappe.cache().delete_value('user_permissions')
@@ -31,6 +24,37 @@ class UserPermission(Document):
frappe.cache().delete_value('user_permissions')
frappe.publish_realtime('update_user_permissions')
+ def validate_user_permission(self):
+ ''' checks for duplicate user permission records'''
+
+ duplicate_exists = frappe.db.get_all(self.doctype, filters={
+ 'allow': self.allow,
+ 'for_value': self.for_value,
+ 'user': self.user,
+ 'applicable_for': cstr(self.applicable_for),
+ 'apply_to_all_doctypes': self.apply_to_all_doctypes,
+ 'name': ['!=', self.name]
+ }, limit=1)
+ if duplicate_exists:
+ frappe.throw(_("User permission already exists"), frappe.DuplicateEntryError)
+
+ def validate_default_permission(self):
+ ''' validate user permission overlap for default value of a particular doctype '''
+ overlap_exists = []
+ if self.is_default:
+ overlap_exists = frappe.get_all(self.doctype, filters={
+ 'allow': self.allow,
+ 'user': self.user,
+ 'is_default': 1,
+ 'name': ['!=', self.name]
+ }, or_filters={
+ 'applicable_for': cstr(self.applicable_for),
+ 'apply_to_all_doctypes': 1
+ }, limit=1)
+ if overlap_exists:
+ ref_link = frappe.get_desk_link(self.doctype, overlap_exists[0].name)
+ frappe.throw(_("{0} has already assigned default value for {1}.".format(ref_link, self.allow)))
+
@frappe.whitelist()
def get_user_permissions(user=None):
'''Get all users permissions for the user as a dict of doctype'''
@@ -52,7 +76,7 @@ def get_user_permissions(user=None):
out = {}
- def add_doc_to_perm(perm, doc_name):
+ def add_doc_to_perm(perm, doc_name, is_default):
# group rules for each type
# for example if allow is "Customer", then build all allowed customers
# in a list
@@ -61,21 +85,22 @@ def get_user_permissions(user=None):
out[perm.allow].append(frappe._dict({
'doc': doc_name,
- 'applicable_for': perm.get('applicable_for')
+ 'applicable_for': perm.get('applicable_for'),
+ 'is_default': is_default
}))
try:
for perm in frappe.get_all('User Permission',
- fields=['allow', 'for_value', 'applicable_for'],
+ fields=['allow', 'for_value', 'applicable_for', 'is_default'],
filters=dict(user=user)):
meta = frappe.get_meta(perm.allow)
- add_doc_to_perm(perm, perm.for_value)
+ add_doc_to_perm(perm, perm.for_value, perm.is_default)
if meta.is_nested_set():
decendants = frappe.db.get_descendants(perm.allow, perm.for_value)
for doc in decendants:
- add_doc_to_perm(perm, doc)
+ add_doc_to_perm(perm, doc, False)
out = frappe._dict(out)
frappe.cache().hset("user_permissions", user, out)
@@ -160,24 +185,25 @@ def add_user_permissions(data):
exists = frappe.db.exists("User Permission", {"user": data.user, "allow": data.doctype, "for_value": data.docname, "apply_to_all_doctypes": 1})
if data.apply_to_all_doctypes == 1 and not exists:
remove_applicable(d, data.user, data.doctype, data.docname)
- insert_user_perm(data.user, data.doctype, data.docname, apply_to_all = 1)
+ insert_user_perm(data.user, data.doctype, data.docname, data.is_default, apply_to_all = 1)
return 1
else:
remove_apply_to_all(data.user, data.doctype, data.docname)
update_applicable(d, data.applicable_doctypes, data.user, data.doctype, data.docname)
for applicable in data.applicable_doctypes :
if applicable not in d:
- insert_user_perm(data.user, data.doctype, data.docname, applicable = applicable)
+ insert_user_perm(data.user, data.doctype, data.docname, data.is_default, applicable = applicable)
elif exists:
- insert_user_perm(data.user, data.doctype, data.docname, applicable = applicable)
+ insert_user_perm(data.user, data.doctype, data.docname, data.is_default, applicable = applicable)
return 1
return 0
-def insert_user_perm(user, doctype, docname, apply_to_all=None, applicable=None):
+def insert_user_perm(user, doctype, docname, is_default=0, apply_to_all=None, applicable=None):
user_perm = frappe.new_doc("User Permission")
user_perm.user = user
user_perm.allow = doctype
user_perm.for_value = docname
+ user_perm.is_default = is_default
if applicable:
user_perm.applicable_for = applicable
user_perm.apply_to_all_doctypes = 0
@@ -210,4 +236,4 @@ def update_applicable(already_applied, to_apply, user, doctype, docname):
AND `applicable_for`=%s
AND `allow`=%s
AND `for_value`=%s
- """,(user, applied, doctype, docname))
\ No newline at end of file
+ """,(user, applied, doctype, docname))
diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js
index 00d829b2a0..a0b553c43a 100644
--- a/frappe/core/doctype/user_permission/user_permission_list.js
+++ b/frappe/core/doctype/user_permission/user_permission_list.js
@@ -16,6 +16,7 @@ frappe.listview_settings['User Permission'] = {
dialog.fields_dict.doctype.set_input(undefined);
dialog.fields_dict.docname.set_input(undefined);
dialog.set_df_property("docname", "hidden", 1);
+ dialog.set_df_property("is_default", "hidden", 1);
dialog.set_df_property("apply_to_all_doctypes", "hidden", 1);
dialog.set_df_property("applicable_doctypes", "hidden", 1);
}
@@ -53,11 +54,16 @@ frappe.listview_settings['User Permission'] = {
}
}
},
+ {
+ fieldname: 'is_default',
+ label: __('Is Default'),
+ fieldtype: 'Check',
+ hidden: 1
+ },
{
fieldname: 'apply_to_all_doctypes',
label: __('Apply to all Documents Types'),
fieldtype: 'Check',
- checked: 1,
hidden: 1,
onchange: function() {
if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){
@@ -205,8 +211,9 @@ frappe.listview_settings['User Permission'] = {
on_doctype_change: function(dialog) {
dialog.set_df_property("docname", "hidden", 0);
dialog.set_df_property("docname", "reqd", 1);
+ dialog.set_df_property("is_default", "hidden", 0);
dialog.set_df_property("apply_to_all_doctypes", "hidden", 0);
- dialog.set_value("apply_to_all_doctypes","checked",1);
+ dialog.set_value("apply_to_all_doctypes", "checked", 1);
},
on_docname_change: function(dialog, options, applicable) {
diff --git a/frappe/core/doctype/version/version.py b/frappe/core/doctype/version/version.py
index 28f3ea5364..284e79cf62 100644
--- a/frappe/core/doctype/version/version.py
+++ b/frappe/core/doctype/version/version.py
@@ -40,6 +40,9 @@ def get_diff(old, new, for_child=False):
],
}'''
+ if not new:
+ return None
+
out = frappe._dict(changed = [], added = [], removed = [], row_changed = [])
for df in new.meta.fields:
if df.fieldtype in no_value_fields and df.fieldtype not in table_fields:
diff --git a/frappe/core/page/dashboard/dashboard.js b/frappe/core/page/dashboard/dashboard.js
index b4cb4d7222..c8b8fc94dc 100644
--- a/frappe/core/page/dashboard/dashboard.js
+++ b/frappe/core/page/dashboard/dashboard.js
@@ -60,7 +60,12 @@ class Dashboard {
show_dashboard(current_dashboard_name) {
if(this.dashboard_name !== current_dashboard_name) {
this.dashboard_name = current_dashboard_name;
- this.page.set_title(this.dashboard_name);
+ let title = this.dashboard_name;
+ if (!this.dashboard_name.toLowerCase().includes(__('dashboard'))) {
+ // ensure dashboard title has "dashboard"
+ title = __('{0} Dashboard', [title]);
+ }
+ this.page.set_title(title);
this.set_dropdown();
this.container.empty();
this.refresh();
diff --git a/frappe/core/report/feedback_ratings/feedback_ratings.js b/frappe/core/report/feedback_ratings/feedback_ratings.js
deleted file mode 100644
index 7d42069e49..0000000000
--- a/frappe/core/report/feedback_ratings/feedback_ratings.js
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.query_reports["Feedback Ratings"] = {
- "filters": [
- {
- "fieldname": "document_type",
- "label": __("Document Type"),
- "fieldtype": "Link",
- "options": "DocType",
- "reqd": 1,
- "default": "Issue",
- "get_query": function() {
- return {
- "query": "frappe.core.report.feedback_ratings.feedback_ratings.get_document_type"
- }
- }
- },
- {
- "fieldname": "document_id",
- "label": __("Document ID"),
- "fieldtype": "Dynamic Link",
- "get_options": function() {
- var document_type = frappe.query_report.get_filter_value('document_type');
- if(!document_type) {
- frappe.throw(__("Please select Document Type first"));
- }
- return document_type;
- }
- },
- {
- "fieldname":"from_date",
- "label": __("From Date"),
- "fieldtype": "Date",
- 'reqd': 1,
- "default": frappe.datetime.add_days(frappe.datetime.nowdate(), -30)
- },
- {
- "fieldname":"to_date",
- "label": __("To Date"),
- "fieldtype": "Date",
- 'reqd': 1,
- "default":frappe.datetime.nowdate()
- }
- ],
-
- get_chart_data: function(columns, result) {
- return {
- data: {
- x: 'Date',
- columns: [
- ['Date'].concat($.map(result, function(d) { return d[0]; })),
- ['Average Feedback'].concat($.map(result, function(d) { return d[1]; }))
- ]
- },
- chart_type: 'line',
-
- }
- }
-}
diff --git a/frappe/core/report/feedback_ratings/feedback_ratings.json b/frappe/core/report/feedback_ratings/feedback_ratings.json
deleted file mode 100644
index 48c10c2e6c..0000000000
--- a/frappe/core/report/feedback_ratings/feedback_ratings.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "add_total_row": 0,
- "apply_user_permissions": 1,
- "creation": "2017-02-05 20:38:21.890174",
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "idx": 2,
- "is_standard": "Yes",
- "modified": "2017-02-24 19:56:51.141147",
- "modified_by": "Administrator",
- "module": "Core",
- "name": "Feedback Ratings",
- "owner": "Administrator",
- "ref_doctype": "Feedback Trigger",
- "report_name": "Feedback Ratings",
- "report_type": "Script Report",
- "roles": [
- {
- "role": "System Manager"
- }
- ]
-}
\ No newline at end of file
diff --git a/frappe/core/report/feedback_ratings/feedback_ratings.py b/frappe/core/report/feedback_ratings/feedback_ratings.py
deleted file mode 100644
index dff832bfba..0000000000
--- a/frappe/core/report/feedback_ratings/feedback_ratings.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-def execute(filters=None):
- columns, data = get_columns(filters), get_data(filters)
- return columns, data
-
-def get_columns(filters):
- return [
- "Date:Date",
- "Average Rating",
- ]
-
-def get_data(filters):
- data = []
- document_type = filters.get("document_type")
- party = filters.get("document_id")
- filters = {
- "reference_doctype": document_type,
- "communication_type": "Feedback",
- "creation": ["Between", [filters.get("from_date"), filters.get("to_date")]]
- }
- fields = ["DATE_FORMAT(DATE(creation),'%m-%d-%Y')", "avg(rating) as rating"]
-
- if not document_type:
- return []
-
- if party:
- filters.update({ "reference_name": party })
-
- party_details = frappe.get_list("Communication", filters=filters, fields=fields,
- order_by="creation", group_by="DATE_FORMAT(DATE(creation),'%m-%d-%Y')", as_list=True)
-
- return party_details or []
-
-@frappe.whitelist()
-def get_document_type(doctype, txt, searchfield, start, page_len, filters):
- """ get the document type """
-
- document_type = []
- txt = "%%%s%%" % txt
-
- document_type = frappe.get_all("Feedback Trigger", filters={ "enabled": 1, "document_type": ("like", txt) },
- fields=["document_type"], as_list=True)
-
- document_type = map(list, document_type)
- to_ignore = [ doc[0] for doc in document_type ]
-
- documents = frappe.get_all("Feedback Request", filters={ "reference_doctype": ["not in", to_ignore] },
- fields=["reference_doctype"], distinct=True, as_list=True)
-
- if documents:
- document_type.extend(documents)
-
- return document_type
diff --git a/frappe/custom/doctype/customize_form/customize_form.js b/frappe/custom/doctype/customize_form/customize_form.js
index 0a6f6d4d54..c503c903eb 100644
--- a/frappe/custom/doctype/customize_form/customize_form.js
+++ b/frappe/custom/doctype/customize_form/customize_form.js
@@ -28,6 +28,11 @@ frappe.ui.form.on("Customize Form", {
$(frm.wrapper).on("grid-make-sortable", function(e, frm) {
frm.trigger("setup_sortable");
});
+
+ $(frm.wrapper).on("grid-move-row", function(e, frm) {
+ frm.trigger("setup_sortable");
+ });
+
},
doc_type: function(frm) {
@@ -57,12 +62,13 @@ frappe.ui.form.on("Customize Form", {
frm.doc.fields.forEach(function(f, i) {
var data_row = frm.page.body.find('[data-fieldname="fields"] [data-idx="'+ f.idx +'"] .data-row');
- if(!f.is_custom_field) {
- data_row.removeClass('sortable-handle');
- } else {
+ if(f.is_custom_field) {
data_row.addClass("highlight");
+ } else {
+ f._sortable = false;
}
});
+ frm.fields_dict.fields.grid.refresh();
},
refresh: function(frm) {
diff --git a/frappe/custom/doctype/customize_form/customize_form.json b/frappe/custom/doctype/customize_form/customize_form.json
index 462f1be56c..5f288fe99c 100644
--- a/frappe/custom/doctype/customize_form/customize_form.json
+++ b/frappe/custom/doctype/customize_form/customize_form.json
@@ -1,694 +1,182 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "DL.####",
- "beta": 0,
- "creation": "2013-01-29 17:55:08",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
+ "autoname": "DL.####",
+ "creation": "2013-01-29 17:55:08",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "field_order": [
+ "doc_type",
+ "properties",
+ "label",
+ "default_print_format",
+ "max_attachments",
+ "allow_copy",
+ "istable",
+ "editable_grid",
+ "quick_entry",
+ "track_changes",
+ "track_views",
+ "image_view",
+ "column_break_5",
+ "title_field",
+ "image_field",
+ "search_fields",
+ "section_break_8",
+ "sort_field",
+ "column_break_10",
+ "sort_order",
+ "fields_section_break",
+ "fields"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "doc_type",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Enter Form Type",
- "length": 0,
- "no_copy": 0,
- "options": "DocType",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "doc_type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Enter Form Type",
+ "options": "DocType"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "doc_type",
- "fieldname": "properties",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "depends_on": "doc_type",
+ "fieldname": "properties",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "label",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Change Label (via Custom Translation)",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "label",
+ "fieldtype": "Data",
+ "label": "Change Label (via Custom Translation)"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "default_print_format",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Default Print Format",
- "length": 0,
- "no_copy": 0,
- "options": "Print Format",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "default_print_format",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Default Print Format",
+ "options": "Print Format"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "max_attachments",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Max Attachments",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "max_attachments",
+ "fieldtype": "Int",
+ "label": "Max Attachments"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "allow_copy",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Hide Copy",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "allow_copy",
+ "fieldtype": "Check",
+ "label": "Hide Copy"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "istable",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Table",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "istable",
+ "fieldtype": "Check",
+ "label": "Is Table",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "istable",
- "fieldname": "editable_grid",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Editable Grid",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "depends_on": "istable",
+ "fieldname": "editable_grid",
+ "fieldtype": "Check",
+ "label": "Editable Grid"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fieldname": "quick_entry",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Quick Entry",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "default": "1",
+ "fieldname": "quick_entry",
+ "fieldtype": "Check",
+ "label": "Quick Entry"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "track_changes",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Track Changes",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "track_changes",
+ "fieldtype": "Check",
+ "label": "Track Changes"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: doc.image_field",
- "fieldname": "image_view",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Image View",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "depends_on": "eval: doc.image_field",
+ "fieldname": "image_view",
+ "fieldtype": "Check",
+ "label": "Image View"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_5",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Use this fieldname to generate title",
- "fieldname": "title_field",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Title Field",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "description": "Use this fieldname to generate title",
+ "fieldname": "title_field",
+ "fieldtype": "Data",
+ "label": "Title Field"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Must be of type \"Attach Image\"",
- "fieldname": "image_field",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Image Field",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "description": "Must be of type \"Attach Image\"",
+ "fieldname": "image_field",
+ "fieldtype": "Data",
+ "label": "Image Field"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Fields separated by comma (,) will be included in the \"Search By\" list of Search dialog box",
- "fieldname": "search_fields",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Search Fields",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "description": "Fields separated by comma (,) will be included in the \"Search By\" list of Search dialog box",
+ "fieldname": "search_fields",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Search Fields"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "doc_type",
- "fieldname": "section_break_8",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "depends_on": "doc_type",
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sort_field",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sort Field",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "sort_field",
+ "fieldtype": "Select",
+ "label": "Sort Field"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_10",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "column_break_10",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sort_order",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sort Order",
- "length": 0,
- "no_copy": 0,
- "options": "ASC\nDESC",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "sort_order",
+ "fieldtype": "Select",
+ "label": "Sort Order",
+ "options": "ASC\nDESC"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "doc_type",
- "description": "Customize Label, Print Hide, Default etc.",
- "fieldname": "fields_section_break",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Fields",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "depends_on": "doc_type",
+ "description": "Customize Label, Print Hide, Default etc.",
+ "fieldname": "fields_section_break",
+ "fieldtype": "Section Break",
+ "label": "Fields"
+ },
{
- "allow_bulk_edit": 1,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "fields",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Fields",
- "length": 0,
- "no_copy": 0,
- "options": "Customize Form Field",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "allow_bulk_edit": 1,
+ "fieldname": "fields",
+ "fieldtype": "Table",
+ "label": "Fields",
+ "options": "Customize Form Field"
+ },
+ {
+ "fieldname": "track_views",
+ "fieldtype": "Check",
+ "label": "Track Views"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 1,
- "icon": "fa fa-glass",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-04-21 16:59:12.752428",
- "modified_by": "Administrator",
- "module": "Custom",
- "name": "Customize Form",
- "owner": "Administrator",
+ ],
+ "hide_toolbar": 1,
+ "icon": "fa fa-glass",
+ "idx": 1,
+ "issingle": 1,
+ "modified": "2019-05-13 18:54:40.610862",
+ "modified_by": "Administrator",
+ "module": "Custom",
+ "name": "Customize Form",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "doc_type",
- "show_name_in_global_search": 0,
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
+ ],
+ "quick_entry": 1,
+ "search_fields": "doc_type",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py
index 333a967dd2..800ce0d462 100644
--- a/frappe/custom/doctype/customize_form/customize_form.py
+++ b/frappe/custom/doctype/customize_form/customize_form.py
@@ -28,6 +28,7 @@ doctype_properties = {
'editable_grid': 'Check',
'max_attachments': 'Int',
'track_changes': 'Check',
+ 'track_views': 'Check',
}
docfield_properties = {
@@ -87,6 +88,9 @@ class CustomizeForm(Document):
if self.doc_type in core_doctypes_list:
return frappe.msgprint(_("Core DocTypes cannot be customized."))
+ if meta.issingle:
+ return frappe.msgprint(_("Single DocTypes cannot be customized."))
+
if meta.custom:
return frappe.msgprint(_("Only standard DocTypes are allowed to be customized from Customize Form."))
@@ -157,7 +161,7 @@ class CustomizeForm(Document):
frappe.db.updatedb(self.doc_type)
if not hasattr(self, 'hide_success') or not self.hide_success:
- frappe.msgprint(_("{0} updated").format(_(self.doc_type)))
+ frappe.msgprint(_("{0} updated").format(_(self.doc_type)), alert=True)
frappe.clear_cache(doctype=self.doc_type)
self.fetch_to_customize()
diff --git a/frappe/database/__init__.py b/frappe/database/__init__.py
index f00c6bf0b4..9d05223044 100644
--- a/frappe/database/__init__.py
+++ b/frappe/database/__init__.py
@@ -23,14 +23,14 @@ def drop_user_and_database(db_name, root_login=None, root_password=None):
import frappe.database.mariadb.setup_db
return frappe.database.mariadb.setup_db.drop_user_and_database(db_name, root_login, root_password)
-def get_db(host=None, user=None, password=None):
+def get_db(host=None, user=None, password=None, port=None):
import frappe
if frappe.conf.db_type == 'postgres':
import frappe.database.postgres.database
- return frappe.database.postgres.database.PostgresDatabase(host, user, password)
+ return frappe.database.postgres.database.PostgresDatabase(host, user, password, port=port)
else:
import frappe.database.mariadb.database
- return frappe.database.mariadb.database.MariaDBDatabase(host, user, password)
+ return frappe.database.mariadb.database.MariaDBDatabase(host, user, password, port=port)
def setup_help_database(help_db_name):
import frappe
@@ -39,4 +39,4 @@ def setup_help_database(help_db_name):
return frappe.database.postgres.setup_db.setup_help_database(help_db_name)
else:
import frappe.database.mariadb.setup_db
- return frappe.database.mariadb.setup_db.setup_help_database(help_db_name)
\ No newline at end of file
+ return frappe.database.mariadb.setup_db.setup_help_database(help_db_name)
diff --git a/frappe/database/database.py b/frappe/database/database.py
index d3b44913fc..a58026982a 100644
--- a/frappe/database/database.py
+++ b/frappe/database/database.py
@@ -46,9 +46,10 @@ class Database(object):
class InvalidColumnName(frappe.ValidationError): pass
- def __init__(self, host=None, user=None, password=None, ac_name=None, use_default=0):
+ def __init__(self, host=None, user=None, password=None, ac_name=None, use_default=0, port=None):
self.setup_type_map()
self.host = host or frappe.conf.db_host or 'localhost'
+ self.port = port or frappe.conf.db_port or ''
self.user = user or frappe.conf.db_name
self.db_name = frappe.conf.db_name
self._conn = None
@@ -153,6 +154,10 @@ class Database(object):
frappe.log(values)
frappe.log(">>>>")
self._cursor.execute(query, values)
+
+ if frappe.flags.in_migrate:
+ self.log_touched_tables(query, values)
+
else:
if debug:
if explain:
@@ -165,6 +170,9 @@ class Database(object):
self._cursor.execute(query)
+ if frappe.flags.in_migrate:
+ self.log_touched_tables(query)
+
if debug:
time_end = time()
frappe.errprint(("Execution time: {0} sec").format(round(time_end - time_start, 2)))
@@ -173,6 +181,10 @@ class Database(object):
if(frappe.conf.db_type == 'postgres'):
self.rollback()
+ if frappe.conf.db_type == 'mariadb' and self.is_syntax_error(e):
+ frappe.errprint('Syntax error in query:')
+ frappe.errprint(query)
+
if ignore_ddl and (self.is_missing_column(e) or self.is_missing_table(e) or self.cant_drop_field_or_key(e)):
pass
else:
@@ -833,7 +845,7 @@ class Database(object):
"""Returns list of column names from given doctype."""
columns = self.get_db_table_columns('tab' + doctype)
if not columns:
- raise self.ProgrammingError
+ raise self.TableMissingError
return columns
def has_column(self, doctype, column):
@@ -912,6 +924,20 @@ class Database(object):
else:
frappe.throw('No conditions provided')
+ def log_touched_tables(self, query, values=None):
+ if values:
+ query = frappe.safe_decode(self._cursor.mogrify(query, values))
+ if query.strip().lower().split()[0] in ('insert', 'delete', 'update', 'alter'):
+ # ([`\"']?) Captures ', " or ` at the begining of the table name (if provided)
+ # (tab([A-Z]\w+)( [A-Z]\w+)*) Captures table names that start with "tab"
+ # and are continued with multiple words that start with a captital letter
+ # e.g. 'tabXxx' or 'tabXxx Xxx' or 'tabXxx Xxx Xxx' and so on
+ # \1 matches the first captured group (quote character) at the end of the table name
+ tables = [groups[1] for groups in re.findall(r'([`"\']?)(tab([A-Z]\w+)( [A-Z]\w+)*)\1', query)]
+ if frappe.flags.touched_tables is None:
+ frappe.flags.touched_tables = set()
+ frappe.flags.touched_tables.update(tables)
+
def enqueue_jobs_after_commit():
if frappe.flags.enqueue_after_commit and len(frappe.flags.enqueue_after_commit) > 0:
diff --git a/frappe/database/mariadb/database.py b/frappe/database/mariadb/database.py
index 69a9cf5e9f..bce705f6a1 100644
--- a/frappe/database/mariadb/database.py
+++ b/frappe/database/mariadb/database.py
@@ -17,6 +17,7 @@ from frappe.database.mariadb.schema import MariaDBTable
class MariaDBDatabase(Database):
ProgrammingError = pymysql.err.ProgrammingError
+ TableMissingError = pymysql.err.ProgrammingError
OperationalError = pymysql.err.OperationalError
InternalError = pymysql.err.InternalError
SQLError = pymysql.err.ProgrammingError
@@ -80,11 +81,11 @@ class MariaDBDatabase(Database):
if usessl:
conn = pymysql.connect(self.host, self.user or '', self.password or '',
- charset='utf8mb4', use_unicode = True, ssl=ssl_params,
+ port=self.port, charset='utf8mb4', use_unicode = True, ssl=ssl_params,
conv = conversions, local_infile = frappe.conf.local_infile)
else:
conn = pymysql.connect(self.host, self.user or '', self.password or '',
- charset='utf8mb4', use_unicode = True, conv = conversions,
+ port=self.port, charset='utf8mb4', use_unicode = True, conv = conversions,
local_infile = frappe.conf.local_infile)
# MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1
@@ -163,6 +164,10 @@ class MariaDBDatabase(Database):
def cant_drop_field_or_key(e):
return e.args[0] == ER.CANT_DROP_FIELD_OR_KEY
+ @staticmethod
+ def is_syntax_error(e):
+ return e.args[0] == ER.PARSE_ERROR
+
def is_primary_key_violation(self, e):
return self.is_duplicate_entry(e) and 'PRIMARY' in cstr(e.args[1])
@@ -282,4 +287,4 @@ class MariaDBDatabase(Database):
self.begin()
def get_database_list(self, target):
- return [d[0] for d in self.sql("SHOW DATABASES;")]
\ No newline at end of file
+ return [d[0] for d in self.sql("SHOW DATABASES;")]
diff --git a/frappe/database/mariadb/framework_mariadb.sql b/frappe/database/mariadb/framework_mariadb.sql
index eae479df05..ad4cd7d5ef 100644
--- a/frappe/database/mariadb/framework_mariadb.sql
+++ b/frappe/database/mariadb/framework_mariadb.sql
@@ -37,6 +37,7 @@ CREATE TABLE `tabDocField` (
`unique` int(1) NOT NULL DEFAULT 0,
`no_copy` int(1) NOT NULL DEFAULT 0,
`allow_on_submit` int(1) NOT NULL DEFAULT 0,
+ `show_preview_popup` int(1) NOT NULL DEFAULT 0,
`trigger` varchar(255) DEFAULT NULL,
`collapsible_depends_on` text,
`depends_on` text,
@@ -49,6 +50,7 @@ CREATE TABLE `tabDocField` (
`description` text,
`in_list_view` int(1) NOT NULL DEFAULT 0,
`in_standard_filter` int(1) NOT NULL DEFAULT 0,
+ `in_preview` int(1) NOT NULL DEFAULT 0,
`read_only` int(1) NOT NULL DEFAULT 0,
`precision` varchar(255) DEFAULT NULL,
`length` int(11) NOT NULL DEFAULT 0,
diff --git a/frappe/database/mariadb/setup_db.py b/frappe/database/mariadb/setup_db.py
index 3cc5365d79..bda3c8b0a7 100644
--- a/frappe/database/mariadb/setup_db.py
+++ b/frappe/database/mariadb/setup_db.py
@@ -4,6 +4,32 @@ import frappe
import os, sys
from frappe.database.db_manager import DbManager
+expected_settings_10_2_earlier = {
+ "innodb_file_format": "Barracuda",
+ "innodb_file_per_table": "ON",
+ "innodb_large_prefix": "ON",
+ "character_set_server": "utf8mb4",
+ "collation_server": "utf8mb4_unicode_ci"
+}
+
+expected_settings_10_3_later = {
+ "character_set_server": "utf8mb4",
+ "collation_server": "utf8mb4_unicode_ci"
+}
+
+
+def get_mariadb_versions():
+ # MariaDB classifies their versions as Major (1st and 2nd number), and Minor (3rd number)
+ # Example: Version 10.3.13 is Major Version = 10.3, Minor Version = 13
+ mariadb_variables = frappe._dict(frappe.db.sql("""show variables"""))
+ version_string = mariadb_variables.get('version').split('-')[0]
+ versions = {}
+ versions['major'] = version_string.split(
+ '.')[0] + '.' + version_string.split('.')[1]
+ versions['minor'] = version_string.split('.')[2]
+ return versions
+
+
def setup_database(force, source_sql, verbose):
frappe.local.session = frappe._dict({'user':'Administrator'})
@@ -54,7 +80,10 @@ def drop_user_and_database(db_name, root_login, root_password):
def bootstrap_database(db_name, verbose, source_sql=None):
frappe.connect(db_name=db_name)
- check_if_ready_for_barracuda()
+ if not check_database_settings():
+ print('Database settings do not match expected values; stopping database setup.')
+ sys.exit(1)
+
import_db_from_sql(source_sql, verbose)
if not 'tabDefaultValue' in frappe.db.get_tables():
print('''Database not installed, this can due to lack of permission, or that the database name exists.
@@ -69,38 +98,33 @@ def import_db_from_sql(source_sql=None, verbose=False):
DbManager(frappe.local.db).restore_database(db_name, source_sql, db_name, frappe.conf.db_password)
if verbose: print("Imported from database %s" % source_sql)
-def check_if_ready_for_barracuda():
+
+def check_database_settings():
+ versions = get_mariadb_versions()
+ if versions['major'] <= '10.2':
+ expected_variables = expected_settings_10_2_earlier
+ else:
+ expected_variables = expected_settings_10_3_later
+
mariadb_variables = frappe._dict(frappe.db.sql("""show variables"""))
- mariadb_minor_version = int(mariadb_variables.get('version').split('-')[0].split('.')[1])
- if mariadb_minor_version < 3:
- check_database(mariadb_variables, {
- "innodb_file_format": "Barracuda",
- "innodb_file_per_table": "ON",
- "innodb_large_prefix": "ON"
- })
- check_database(mariadb_variables, {
- "character_set_server": "utf8mb4",
- "collation_server": "utf8mb4_unicode_ci"
- })
+ # Check each expected value vs. actuals:
+ result = True
+ for key, expected_value in expected_variables.items():
+ if mariadb_variables.get(key) != expected_value:
+ print("For key %s. Expected value %s, found value %s" %
+ (key, expected_value, mariadb_variables.get(key)))
+ result = False
+ if not result:
+ site = frappe.local.site
+ msg = ("Creation of your site - {x} failed because MariaDB is not properly {sep}"
+ "configured. If using version 10.2.x or earlier, make sure you use the {sep}"
+ "the Barracuda storage engine. {sep}{sep}"
+ "Please verify the settings above in MariaDB's my.cnf. Restart MariaDB. And {sep}"
+ "then run `bench new-site {x}` again.{sep2}"
+ "").format(x=site, sep2="\n"*2, sep="\n")
+ print_db_config(msg)
+ return result
-def check_database(mariadb_variables, variables_dict):
- mariadb_minor_version = int(mariadb_variables.get('version').split('-')[0].split('.')[1])
- for key, value in variables_dict.items():
- if mariadb_variables.get(key) != value:
- site = frappe.local.site
- msg = ("Creation of your site - {x} failed because MariaDB is not properly {sep}"
- "configured to use the Barracuda storage engine. {sep}"
- "Please add the settings below to MariaDB's my.cnf, restart MariaDB then {sep}"
- "run `bench new-site {x}` again.{sep2}"
- "").format(x=site, sep2="\n"*2, sep="\n")
-
- if mariadb_minor_version < 3:
- print_db_config(msg, expected_config_for_barracuda_2)
- else:
- print_db_config(msg, expected_config_for_barracuda_3)
- raise frappe.exceptions.ImproperDBConfigurationError(
- reason="MariaDB default file format is not Barracuda"
- )
def get_root_connection(root_login, root_password):
import getpass
@@ -118,31 +142,8 @@ def get_root_connection(root_login, root_password):
return frappe.local.flags.root_connection
-def print_db_config(explanation, config_text):
+
+def print_db_config(explanation):
print("="*80)
print(explanation)
- print(config_text)
print("="*80)
-
-expected_config_for_barracuda_2 = """
-[mysqld]
-innodb-file-format=barracuda
-innodb-file-per-table=1
-innodb-large-prefix=1
-character-set-client-handshake = FALSE
-character-set-server = utf8mb4
-collation-server = utf8mb4_unicode_ci
-
-[mysql]
-default-character-set = utf8mb4
-"""
-
-expected_config_for_barracuda_3 = """
-[mysqld]
-character-set-client-handshake = FALSE
-character-set-server = utf8mb4
-collation-server = utf8mb4_unicode_ci
-
-[mysql]
-default-character-set = utf8mb4
-"""
diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py
index 4b8a4ae500..b219aac13a 100644
--- a/frappe/database/postgres/database.py
+++ b/frappe/database/postgres/database.py
@@ -21,6 +21,7 @@ psycopg2.extensions.register_type(DEC2FLOAT)
class PostgresDatabase(Database):
ProgrammingError = psycopg2.ProgrammingError
+ TableMissingError = psycopg2.ProgrammingError
OperationalError = psycopg2.OperationalError
InternalError = psycopg2.InternalError
SQLError = psycopg2.ProgrammingError
@@ -63,10 +64,10 @@ class PostgresDatabase(Database):
def get_connection(self):
# warnings.filterwarnings('ignore', category=psycopg2.Warning)
- conn = psycopg2.connect('host={} dbname={}'.format(self.host, self.user))
+ conn = psycopg2.connect('host={} dbname={} user={} password={} port={}'.format(
+ self.host, self.user, self.user, self.password, self.port
+ ))
conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) # TODO: Remove this
- # conn = psycopg2.connect('host={} dbname={} user={} password={}'.format(self.host,
- # self.user, self.user, self.password))
return conn
@@ -309,4 +310,4 @@ def replace_locate_with_strpos(query):
# strpos is the locate equivalent in postgres
if re.search(r'locate\(', query, flags=re.IGNORECASE):
query = re.sub(r'locate\(([^,]+),([^)]+)\)', r'strpos(\2, \1)', query, flags=re.IGNORECASE)
- return query
\ No newline at end of file
+ return query
diff --git a/frappe/database/postgres/framework_postgres.sql b/frappe/database/postgres/framework_postgres.sql
index eb82f3ed97..756917ca97 100644
--- a/frappe/database/postgres/framework_postgres.sql
+++ b/frappe/database/postgres/framework_postgres.sql
@@ -37,6 +37,7 @@ CREATE TABLE "tabDocField" (
"unique" smallint NOT NULL DEFAULT 0,
"no_copy" smallint NOT NULL DEFAULT 0,
"allow_on_submit" smallint NOT NULL DEFAULT 0,
+ "show_preview_popup" smallint NOT NULL DEFAULT 0,
"trigger" varchar(255) DEFAULT NULL,
"collapsible_depends_on" text,
"depends_on" text,
@@ -49,6 +50,7 @@ CREATE TABLE "tabDocField" (
"description" text,
"in_list_view" smallint NOT NULL DEFAULT 0,
"in_standard_filter" smallint NOT NULL DEFAULT 0,
+ "in_preview" smallint NOT NULL DEFAULT 0,
"read_only" smallint NOT NULL DEFAULT 0,
"precision" varchar(255) DEFAULT NULL,
"length" bigint NOT NULL DEFAULT 0,
diff --git a/frappe/database/postgres/schema.py b/frappe/database/postgres/schema.py
index 05b6b19a9a..b5129b60bb 100644
--- a/frappe/database/postgres/schema.py
+++ b/frappe/database/postgres/schema.py
@@ -40,7 +40,20 @@ class PostgresTable(DBTable):
query.append("ADD COLUMN `{}` {}".format(col.fieldname, col.get_definition()))
for col in self.change_type:
- query.append("ALTER COLUMN `{}` TYPE {}".format(col.fieldname, get_definition(col.fieldtype, precision=col.precision, length=col.length)))
+ using_clause = ""
+ if col.fieldtype in ("Datetime"):
+ # The USING option of SET DATA TYPE can actually specify any expression
+ # involving the old values of the row
+ # read more https://www.postgresql.org/docs/9.1/sql-altertable.html
+ using_clause = "USING {}::timestamp without time zone".format(col.fieldname)
+ elif col.fieldtype in ("Check"):
+ using_clause = "USING {}::smallint".format(col.fieldname)
+
+ query.append("ALTER COLUMN {0} TYPE {1} {2}".format(
+ col.fieldname,
+ get_definition(col.fieldtype, precision=col.precision, length=col.length),
+ using_clause)
+ )
for col in self.set_default:
if col.fieldname=="name":
@@ -93,4 +106,4 @@ class PostgresTable(DBTable):
fieldname, self.table_name)))
raise e
else:
- raise e
\ No newline at end of file
+ raise e
diff --git a/frappe/database/postgres/setup_db.py b/frappe/database/postgres/setup_db.py
index 0209d65839..7ccd86a26e 100644
--- a/frappe/database/postgres/setup_db.py
+++ b/frappe/database/postgres/setup_db.py
@@ -1,4 +1,5 @@
import frappe, subprocess, os
+from six.moves import input
def setup_database(force, source_sql, verbose):
root_conn = get_root_connection()
@@ -10,9 +11,16 @@ def setup_database(force, source_sql, verbose):
frappe.conf.db_password))
root_conn.sql("GRANT ALL PRIVILEGES ON DATABASE `{0}` TO {0}".format(frappe.conf.db_name))
+ # we can't pass psql password in arguments in postgresql as mysql. So
+ # set password connection parameter in environment variable
+ subprocess_env = os.environ.copy()
+ subprocess_env['PGPASSWORD'] = str(frappe.conf.db_password)
# bootstrap db
- subprocess.check_output(['psql', frappe.conf.db_name, '-qf',
- os.path.join(os.path.dirname(__file__), 'framework_postgres.sql')])
+ subprocess.check_output([
+ 'psql', frappe.conf.db_name, '-h', 'localhost', '-U',
+ frappe.conf.db_name, '-f',
+ os.path.join(os.path.dirname(__file__), 'framework_postgres.sql')
+ ], env=subprocess_env)
frappe.connect()
@@ -24,17 +32,20 @@ def setup_help_database(help_db_name):
root_conn.sql("CREATE user {0} password '{1}'".format(help_db_name, help_db_name))
root_conn.sql("GRANT ALL PRIVILEGES ON DATABASE `{0}` TO {0}".format(help_db_name))
-def get_root_connection(root_login='postgres', root_password=None):
+def get_root_connection(root_login=None, root_password=None):
import getpass
if not frappe.local.flags.root_connection:
if not root_login:
- root_login = 'root'
+ root_login = frappe.conf.get("root_login") or None
+
+ if not root_login:
+ root_login = input("Enter postgres super user: ")
if not root_password:
root_password = frappe.conf.get("root_password") or None
if not root_password:
- root_password = getpass.getpass("Postgres root password: ")
+ root_password = getpass.getpass("Postgres super user password: ")
frappe.local.flags.root_connection = frappe.database.get_db(user=root_login, password=root_password)
diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js
index 68396f4c6a..ba00d81143 100644
--- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js
+++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js
@@ -10,7 +10,7 @@ frappe.ui.form.on('Dashboard Chart', {
},
refresh: function(frm) {
- frm.filters = null;
+ frm.chart_filters = null;
frm.set_df_property("filters_section", "hidden", 1);
frm.trigger('update_options');
},
@@ -58,7 +58,7 @@ frappe.ui.form.on('Dashboard Chart', {
if (['Date', 'Datetime'].includes(df.fieldtype)) {
date_fields.push({label: df.label, value: df.fieldname});
}
- if (['In', 'Float', 'Currency', 'Percent'].includes(df.fieldtype)) {
+ if (['Int', 'Float', 'Currency', 'Percent'].includes(df.fieldtype)) {
value_fields.push({label: df.label, value: df.fieldname});
}
});
@@ -72,21 +72,26 @@ frappe.ui.form.on('Dashboard Chart', {
},
show_filters: function(frm) {
- if (frm.filters) {
+ if (frm.chart_filters && frm.chart_filters.length) {
frm.trigger('render_filters_table');
} else {
if (frm.doc.chart_type==='Custom') {
- frappe.xcall('frappe.desk.doctype.dashboard_chart_source.dashboard_chart_source.get_config', {name: frm.doc.source})
- .then(config => {
- frappe.dom.eval(config);
- frm.filters = frappe.dashboards.chart_sources[frm.doc.source].filters;
- frm.trigger('render_filters_table');
- });
+ if (frm.doc.source) {
+ frappe.xcall('frappe.desk.doctype.dashboard_chart_source.dashboard_chart_source.get_config', {name: frm.doc.source})
+ .then(config => {
+ frappe.dom.eval(config);
+ frm.chart_filters = frappe.dashboards.chart_sources[frm.doc.source].filters;
+ frm.trigger('render_filters_table');
+ });
+ } else {
+ frm.chart_filters = [];
+ frm.trigger('render_filters_table');
+ }
} else {
// standard filters
if (frm.doc.document_type) {
// allow all link and select fields as filters
- frm.filters = [];
+ frm.chart_filters = [];
frappe.model.with_doctype(frm.doc.document_type, () => {
frappe.get_meta(frm.doc.document_type).fields.map(df => {
if (['Link', 'Select'].includes(df.fieldtype)) {
@@ -95,12 +100,11 @@ frappe.ui.form.on('Dashboard Chart', {
// nothing is mandatory
_df.reqd = 0;
_df.default = null;
+ _df.read_only = 0;
+ _df.permlevel = 1;
+ _df.hidden = 0;
- // no default
-
- if (!df.read_only && !df.hidden) {
- frm.filters.push(_df);
- }
+ frm.chart_filters.push(_df);
}
frm.trigger('render_filters_table');
});
@@ -113,7 +117,7 @@ frappe.ui.form.on('Dashboard Chart', {
render_filters_table: function(frm) {
frm.set_df_property("filters_section", "hidden", 0);
- let fields = frm.filters;
+ let fields = frm.chart_filters;
let wrapper = $(frm.get_field('filters_json').wrapper).empty();
let table = $(`
diff --git a/frappe/desk/doctype/dashboard_chart/test_dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/test_dashboard_chart.py
index ca55d9254a..970f937020 100644
--- a/frappe/desk/doctype/dashboard_chart/test_dashboard_chart.py
+++ b/frappe/desk/doctype/dashboard_chart/test_dashboard_chart.py
@@ -8,6 +8,10 @@ from frappe.utils import getdate
from frappe.desk.doctype.dashboard_chart.dashboard_chart import (get,
get_period_ending)
+from datetime import datetime
+from dateutil.relativedelta import relativedelta
+import calendar
+
class TestDashboardChart(unittest.TestCase):
def test_period_ending(self):
self.assertEqual(get_period_ending('2019-04-10', 'Daily'),
@@ -48,21 +52,13 @@ class TestDashboardChart(unittest.TestCase):
timeseries = 1
)).insert()
- result = get(chart_name ='Test Dashboard Chart',
- to_date = '2019-04-11', refresh = 1)
- self.assertEqual(result.get('labels')[0], '2018-04-30')
- self.assertEqual(result.get('labels')[1], '2018-05-31')
- self.assertEqual(result.get('labels')[2], '2018-06-30')
- self.assertEqual(result.get('labels')[3], '2018-07-31')
- self.assertEqual(result.get('labels')[4], '2018-08-31')
- self.assertEqual(result.get('labels')[5], '2018-09-30')
- self.assertEqual(result.get('labels')[6], '2018-10-31')
- self.assertEqual(result.get('labels')[7], '2018-11-30')
- self.assertEqual(result.get('labels')[8], '2018-12-31')
- self.assertEqual(result.get('labels')[9], '2019-01-31')
- self.assertEqual(result.get('labels')[10], '2019-02-28')
- self.assertEqual(result.get('labels')[11], '2019-03-31')
- self.assertEqual(result.get('labels')[12], '2019-04-30')
+ cur_date = datetime.now() - relativedelta(years=1)
+
+ result = get(chart_name ='Test Dashboard Chart', refresh = 1)
+ for idx in range(13):
+ month = str(cur_date.year) + '-' + str(cur_date.strftime('%m')) + '-' + str(calendar.monthrange(cur_date.year, cur_date.month)[1])
+ self.assertEqual(result.get('labels')[idx], month)
+ cur_date += relativedelta(months=1)
# self.assertEqual(result.get('datasets')[0].get('values')[:-1],
# [44, 28, 8, 11, 2, 6, 18, 6, 4, 5, 15, 13])
@@ -87,21 +83,13 @@ class TestDashboardChart(unittest.TestCase):
timeseries = 1
)).insert()
- result = get(chart_name ='Test Empty Dashboard Chart',
- to_date = '2019-04-11', refresh = 1)
- self.assertEqual(result.get('labels')[0], '2018-04-30')
- self.assertEqual(result.get('labels')[1], '2018-05-31')
- self.assertEqual(result.get('labels')[2], '2018-06-30')
- self.assertEqual(result.get('labels')[3], '2018-07-31')
- self.assertEqual(result.get('labels')[4], '2018-08-31')
- self.assertEqual(result.get('labels')[5], '2018-09-30')
- self.assertEqual(result.get('labels')[6], '2018-10-31')
- self.assertEqual(result.get('labels')[7], '2018-11-30')
- self.assertEqual(result.get('labels')[8], '2018-12-31')
- self.assertEqual(result.get('labels')[9], '2019-01-31')
- self.assertEqual(result.get('labels')[10], '2019-02-28')
- self.assertEqual(result.get('labels')[11], '2019-03-31')
- self.assertEqual(result.get('labels')[12], '2019-04-30')
+ cur_date = datetime.now() - relativedelta(years=1)
+
+ result = get(chart_name ='Test Empty Dashboard Chart', refresh = 1)
+ for idx in range(13):
+ month = str(cur_date.year) + '-' + str(cur_date.strftime('%m')) + '-' + str(calendar.monthrange(cur_date.year, cur_date.month)[1])
+ self.assertEqual(result.get('labels')[idx], month)
+ cur_date += relativedelta(months=1)
frappe.db.rollback()
@@ -126,24 +114,16 @@ class TestDashboardChart(unittest.TestCase):
timeseries = 1
)).insert()
- result = get(chart_name ='Test Empty Dashboard Chart 2',
- to_date = '2019-04-11', refresh = 1)
- self.assertEqual(result.get('labels')[0], '2018-04-30')
- self.assertEqual(result.get('labels')[1], '2018-05-31')
- self.assertEqual(result.get('labels')[2], '2018-06-30')
- self.assertEqual(result.get('labels')[3], '2018-07-31')
- self.assertEqual(result.get('labels')[4], '2018-08-31')
- self.assertEqual(result.get('labels')[5], '2018-09-30')
- self.assertEqual(result.get('labels')[6], '2018-10-31')
- self.assertEqual(result.get('labels')[7], '2018-11-30')
- self.assertEqual(result.get('labels')[8], '2018-12-31')
- self.assertEqual(result.get('labels')[9], '2019-01-31')
- self.assertEqual(result.get('labels')[10], '2019-02-28')
- self.assertEqual(result.get('labels')[11], '2019-03-31')
- self.assertEqual(result.get('labels')[12], '2019-04-30')
+ cur_date = datetime.now() - relativedelta(years=1)
+
+ result = get(chart_name ='Test Empty Dashboard Chart 2', refresh = 1)
+ for idx in range(13):
+ month = str(cur_date.year) + '-' + str(cur_date.strftime('%m')) + '-' + str(calendar.monthrange(cur_date.year, cur_date.month)[1])
+ self.assertEqual(result.get('labels')[idx], month)
+ cur_date += relativedelta(months=1)
# only 1 data point with value
- self.assertEqual(result.get('datasets')[0].get('values')[2], 1)
+ self.assertEqual(result.get('datasets')[0].get('values')[2], 0)
frappe.db.rollback()
diff --git a/frappe/desk/doctype/event/event.py b/frappe/desk/doctype/event/event.py
index 04f7455e2d..d99cc64436 100644
--- a/frappe/desk/doctype/event/event.py
+++ b/frappe/desk/doctype/event/event.py
@@ -43,10 +43,17 @@ class Event(Document):
def sync_communication(self):
if self.event_participants:
for participant in self.event_participants:
- communication_name = frappe.db.get_value("Communication", dict(reference_doctype=self.doctype, reference_name=self.name, timeline_doctype=participant.reference_doctype, timeline_name=participant.reference_docname), "name")
- if communication_name:
- communication = frappe.get_doc("Communication", communication_name)
- self.update_communication(participant, communication)
+ comms = frappe.get_list("Communication", filters=[
+ ["Communication", "reference_doctype", "=", self.doctype],
+ ["Communication", "reference_name", "=", self.name],
+ ["Dynamic Link", "link_doctype", "=", participant.reference_doctype],
+ ["Dynamic Link", "link_name", "=", participant.reference_docname]
+ ], fields=["name"])
+
+ if comms:
+ for comm in comms:
+ communication = frappe.get_doc("Communication", comm.name)
+ self.update_communication(participant, communication)
else:
meta = frappe.get_meta(participant.reference_doctype)
if hasattr(meta, "allow_events_in_timeline") and meta.allow_events_in_timeline==1:
@@ -62,12 +69,11 @@ class Event(Document):
communication.subject = self.subject
communication.content = self.description if self.description else self.subject
communication.communication_date = self.starts_on
- communication.timeline_doctype = participant.reference_doctype
- communication.timeline_name = participant.reference_docname
communication.reference_doctype = self.doctype
communication.reference_name = self.name
communication.communication_medium = communication_mapping[self.event_category] if self.event_category else ""
communication.status = "Linked"
+ communication.add_link(participant.reference_doctype, participant.reference_docname)
communication.save(ignore_permissions=True)
@frappe.whitelist()
@@ -76,9 +82,18 @@ def delete_communication(event, reference_doctype, reference_docname):
if isinstance(event, string_types):
event = json.loads(event)
- communication_name = frappe.db.get_value("Communication", dict(reference_doctype=event["doctype"], reference_name=event["name"], timeline_doctype=deleted_participant.reference_doctype, timeline_name=deleted_participant.reference_docname), "name")
- if communication_name:
- deletion = frappe.get_doc("Communication", communication_name).delete()
+ comms = frappe.get_list("Communication", filters=[
+ ["Communication", "reference_doctype", "=", event.get("doctype")],
+ ["Communication", "reference_name", "=", event.get("name")],
+ ["Dynamic Link", "link_doctype", "=", deleted_participant.reference_doctype],
+ ["Dynamic Link", "link_name", "=", deleted_participant.reference_docname]
+ ], fields=["name"])
+
+ if comms:
+ deletion = []
+ for comm in comms:
+ delete = frappe.get_doc("Communication", comm.name).delete()
+ deletion.append(delete)
return deletion
diff --git a/frappe/desk/doctype/todo/todo.json b/frappe/desk/doctype/todo/todo.json
index 09b0610215..4b70086648 100644
--- a/frappe/desk/doctype/todo/todo.json
+++ b/frappe/desk/doctype/todo/todo.json
@@ -21,6 +21,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "description_and_status",
"fieldtype": "Section Break",
"hidden": 0,
@@ -53,6 +54,7 @@
"collapsible": 0,
"columns": 0,
"default": "Open",
+ "fetch_if_empty": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 0,
@@ -86,6 +88,7 @@
"collapsible": 0,
"columns": 0,
"default": "Medium",
+ "fetch_if_empty": 0,
"fieldname": "priority",
"fieldtype": "Select",
"hidden": 0,
@@ -120,6 +123,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
@@ -150,6 +154,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "color",
"fieldtype": "Color",
"hidden": 0,
@@ -157,7 +162,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 1,
+ "in_list_view": 0,
"in_standard_filter": 0,
"label": "Color",
"length": 0,
@@ -182,6 +187,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "date",
"fieldtype": "Date",
"hidden": 0,
@@ -189,7 +195,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 1,
+ "in_list_view": 0,
"in_standard_filter": 1,
"label": "Due Date",
"length": 0,
@@ -215,6 +221,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "owner",
"fieldtype": "Link",
"hidden": 0,
@@ -247,6 +254,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "description_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -279,6 +287,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"hidden": 0,
@@ -314,6 +323,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"hidden": 0,
@@ -345,6 +355,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "reference_type",
"fieldtype": "Link",
"hidden": 0,
@@ -352,7 +363,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
"in_standard_filter": 0,
"label": "Reference Type",
"length": 0,
@@ -379,6 +390,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"hidden": 0,
@@ -413,6 +425,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_10",
"fieldtype": "Column Break",
"hidden": 0,
@@ -443,6 +456,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "role",
"fieldtype": "Link",
"hidden": 0,
@@ -477,6 +491,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "assigned_by",
"fieldtype": "Link",
"hidden": 0,
@@ -510,6 +525,7 @@
"collapsible": 0,
"columns": 0,
"fetch_from": "assigned_by.full_name",
+ "fetch_if_empty": 0,
"fieldname": "assigned_by_full_name",
"fieldtype": "Read Only",
"hidden": 0,
@@ -543,6 +559,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "sender",
"fieldtype": "Data",
"hidden": 1,
@@ -575,6 +592,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "assignment_rule",
"fieldtype": "Link",
"hidden": 0,
@@ -603,17 +621,16 @@
}
],
"has_web_view": 0,
- "hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-check",
"idx": 2,
- "image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-03-07 16:11:25.764549",
+ "menu_index": 0,
+ "modified": "2019-04-24 15:45:23.290491",
"modified_by": "Administrator",
"module": "Desk",
"name": "ToDo",
@@ -660,7 +677,6 @@
],
"quick_entry": 1,
"read_only": 0,
- "read_only_onload": 0,
"search_fields": "description, reference_type, reference_name",
"show_name_in_global_search": 0,
"sort_order": "DESC",
diff --git a/frappe/desk/doctype/todo/todo.py b/frappe/desk/doctype/todo/todo.py
index 45c3874806..16530c23dc 100644
--- a/frappe/desk/doctype/todo/todo.py
+++ b/frappe/desk/doctype/todo/todo.py
@@ -43,8 +43,11 @@ class ToDo(Document):
def on_trash(self):
# unlink todo from linked comments
- frappe.db.sql("""update `tabCommunication` set link_doctype=null, link_name=null
- where link_doctype=%(doctype)s and link_name=%(name)s""", {"doctype": self.doctype, "name": self.name})
+ frappe.db.sql("""
+ delete from `tabDynamic Link`
+ where link_doctype=%(doctype)s and link_name=%(name)s""", {
+ "doctype": self.doctype, "name": self.name
+ })
self.update_in_reference()
@@ -94,7 +97,7 @@ def get_permission_query_conditions(user):
if "System Manager" in frappe.get_roles(user):
return None
else:
- return """(tabToDo.owner = {user} or tabToDo.assigned_by = {user})"""\
+ return """(`tabToDo`.owner = {user} or `tabToDo`.assigned_by = {user})"""\
.format(user=frappe.db.escape(user))
def has_permission(doc, user):
@@ -108,4 +111,4 @@ def new_todo(description):
frappe.get_doc({
'doctype': 'ToDo',
'description': description
- }).insert()
\ No newline at end of file
+ }).insert()
diff --git a/frappe/desk/doctype/todo/todo_list.js b/frappe/desk/doctype/todo/todo_list.js
index 6200e85dca..53564cc017 100644
--- a/frappe/desk/doctype/todo/todo_list.js
+++ b/frappe/desk/doctype/todo/todo_list.js
@@ -1,4 +1,7 @@
frappe.listview_settings['ToDo'] = {
+ hide_name_column: true,
+ add_fields: ["reference_type", "reference_name"],
+
onload: function(me) {
if (!frappe.route_options) {
frappe.route_options = {
@@ -8,7 +11,22 @@ frappe.listview_settings['ToDo'] = {
}
me.page.set_title(__("To Do"));
},
- hide_name_column: true,
+
+ button: {
+ show: function(doc) {
+ return doc.reference_name;
+ },
+ get_label: function() {
+ return __('Open');
+ },
+ get_description: function(doc) {
+ return __('Open {0}', [`${doc.reference_type} ${doc.reference_name}`])
+ },
+ action: function(doc) {
+ frappe.set_route('Form', doc.reference_type, doc.reference_name);
+ }
+ },
+
refresh: function(me) {
if (me.todo_sidebar_setup) return;
@@ -19,5 +37,4 @@ frappe.listview_settings['ToDo'] = {
me.todo_sidebar_setup = true;
},
- add_fields: ["reference_type", "reference_name"],
}
\ No newline at end of file
diff --git a/frappe/desk/form/assign_to.py b/frappe/desk/form/assign_to.py
index 4b3a607ec5..38856d5068 100644
--- a/frappe/desk/form/assign_to.py
+++ b/frappe/desk/form/assign_to.py
@@ -7,6 +7,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.desk.form.document_follow import follow_document
+from frappe.utils import cint
import frappe.share
class DuplicateToDoError(frappe.ValidationError): pass
@@ -177,7 +178,7 @@ def notify_assignment(assigned_by, owner, doc_type, doc_name, action='CLOSE',
'notify': notify
}
- if arg and arg.get("notify"):
+ if arg and cint(arg.get("notify")):
_notify(arg)
def _notify(args):
diff --git a/frappe/desk/form/document_follow.py b/frappe/desk/form/document_follow.py
index de04ef35af..333e9e1333 100644
--- a/frappe/desk/form/document_follow.py
+++ b/frappe/desk/form/document_follow.py
@@ -54,8 +54,8 @@ def unfollow_document(doctype, doc_name, user):
return 1
return 0
-def get_message(doc_name, doctype, frequency):
- activity_list = get_version(doctype, doc_name, frequency) + get_comments(doctype, doc_name, frequency)
+def get_message(doc_name, doctype, frequency, user):
+ activity_list = get_version(doctype, doc_name, frequency, user) + get_comments(doctype, doc_name, frequency, user)
return sorted(activity_list, key=lambda k: k["time"], reverse=True)
def send_email_alert(receiver, docinfo, timeline):
@@ -98,7 +98,7 @@ def send_document_follow_mails(frequency):
valid_document_follows = []
if user_frequency == frequency:
for d in grouped_by_user[user]:
- content = get_message(d.ref_docname, d.ref_doctype, frequency)
+ content = get_message(d.ref_docname, d.ref_doctype, frequency, user)
if content:
message = message + content
valid_document_follows.append({
@@ -107,13 +107,13 @@ def send_document_follow_mails(frequency):
"reference_url": get_url_to_form(d.ref_doctype, d.ref_docname)
})
- if message:
+ if message and frappe.db.get_value("User", user, "document_follow_notify", ignore=True):
send_email_alert(user, valid_document_follows, message)
-def get_version(doctype, doc_name, frequency):
+def get_version(doctype, doc_name, frequency, user):
timeline = []
- filters = get_filters("docname", doc_name, frequency)
+ filters = get_filters("docname", doc_name, frequency, user)
version = frappe.get_all("Version",
filters=filters,
fields=["ref_doctype", "data", "modified", "modified", "modified_by"]
@@ -134,9 +134,9 @@ def get_version(doctype, doc_name, frequency):
return timeline
-def get_comments(doctype, doc_name, frequency):
+def get_comments(doctype, doc_name, frequency, user):
timeline = []
- filters = get_filters("reference_name", doc_name, frequency)
+ filters = get_filters("reference_name", doc_name, frequency, user)
comments = frappe.get_all("Comment",
filters=filters,
fields=["content", "modified", "modified_by", "comment_type"]
@@ -255,26 +255,29 @@ def send_daily_updates():
def send_weekly_updates():
send_document_follow_mails("Weekly")
-def get_filters(search_by, name, frequency):
+def get_filters(search_by, name, frequency, user):
filters = []
if frequency == "Weekly":
filters = [
[search_by, "=", name],
["modified", ">", frappe.utils.add_days(frappe.utils.nowdate(),-7)],
- ["modified", "<", frappe.utils.nowdate()]
+ ["modified", "<", frappe.utils.nowdate()],
+ ["modified_by", "!=", user]
]
elif frequency == "Daily":
filters = [
[search_by, "=", name],
["modified", ">", frappe.utils.add_days(frappe.utils.nowdate(),-1)],
- ["modified", "<", frappe.utils.nowdate()]
+ ["modified", "<", frappe.utils.nowdate()],
+ ["modified_by", "!=", user]
]
elif frequency == "Hourly":
filters = [
[search_by, "=", name],
- ["modified", ">", frappe.utils.add_to_date(frappe.utils.now_datetime(), 0, 0, 0, -1)],
- ["modified", "<", frappe.utils.now_datetime()]
+ ["modified", ">", frappe.utils.add_to_date(frappe.utils.now_datetime(), hours=-1)],
+ ["modified", "<", frappe.utils.now_datetime()],
+ ["modified_by", "!=", user]
]
return filters
diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py
index 3107c97895..2985a8858e 100644
--- a/frappe/desk/form/load.py
+++ b/frappe/desk/form/load.py
@@ -47,9 +47,6 @@ def getdoc(doctype, name, user=None):
frappe.errprint(frappe.utils.get_traceback())
raise
- if doc and not name.startswith('_'):
- frappe.get_user().update_recent(doctype, name)
-
doc.add_seen()
frappe.response.docs.append(doc)
@@ -100,13 +97,16 @@ def get_docinfo(doc=None, doctype=None, name=None):
"assignments": get_assignments(doc.doctype, doc.name),
"permissions": get_doc_permissions(doc),
"shared": frappe.share.get_users(doc.doctype, doc.name),
- "rating": get_feedback_rating(doc.doctype, doc.name),
"views": get_view_logs(doc.doctype, doc.name),
"energy_point_logs": get_point_logs(doc.doctype, doc.name),
- "is_document_followed": is_document_followed(doc.doctype, doc.name, frappe.session.user),
- "document_follow_enabled": frappe.db.get_value("User", frappe.session.user, "document_follow_notify")
+ "milestones": get_milestones(doc.doctype, doc.name),
+ "is_document_followed": is_document_followed(doc.doctype, doc.name, frappe.session.user)
}
+def get_milestones(doctype, name):
+ return frappe.db.get_all('Milestone', fields = ['creation', 'owner', 'track_field', 'value'],
+ filters=dict(reference_type=doctype, reference_name=name))
+
def get_attachments(dt, dn):
return frappe.get_all("File", fields=["name", "file_name", "file_url", "is_private"],
filters = {"attached_to_name": dn, "attached_to_doctype": dt})
@@ -160,36 +160,50 @@ def get_communication_data(doctype, name, start=0, limit=20, after=None, fields=
group_by=None, as_dict=True):
'''Returns list of communications for a given document'''
if not fields:
- fields = '''`name`, `communication_type`,`communication_medium`, `comment_type`,
- `communication_date`, `content`, `sender`, `sender_full_name`,
- `creation`, `subject`, `delivery_status`, `_liked_by`,
- `timeline_doctype`, `timeline_name`, `reference_doctype`, `reference_name`,
- `link_doctype`, `link_name`, `read_by_recipient`, `rating`, 'Communication' AS `doctype`'''
+ fields = '''
+ `tabCommunication`.name, `tabCommunication`.communication_type, `tabCommunication`.communication_medium,
+ `tabCommunication`.comment_type, `tabCommunication`.communication_date, `tabCommunication`.content,
+ `tabCommunication`.sender, `tabCommunication`.sender_full_name, `tabCommunication`.cc, `tabCommunication`.bcc,
+ `tabCommunication`.creation, `tabCommunication`.subject, `tabCommunication`.delivery_status,
+ `tabCommunication`._liked_by, `tabCommunication`.reference_doctype, `tabCommunication`.reference_name,
+ `tabCommunication`.read_by_recipient, `tabCommunication`.rating
+ '''
- conditions = '''communication_type in ('Communication', 'Feedback')
- and (
- (reference_doctype=%(doctype)s and reference_name=%(name)s)
+ conditions = '''
+ `tabCommunication`.communication_type in ('Communication', 'Feedback')
+ and (
+ (`tabCommunication`.reference_doctype=%(doctype)s and `tabCommunication`.reference_name=%(name)s)
or (
- (timeline_doctype=%(doctype)s and timeline_name=%(name)s)
- and (communication_type='Communication')
+ (`tabDynamic Link`.link_doctype=%(doctype)s and `tabDynamic Link`.link_name=%(name)s)
+ and (`tabCommunication`.communication_type='Communication')
)
- )'''
-
+ )
+ '''
if after:
# find after a particular date
- conditions+= ' and creation > {0}'.format(after)
+ conditions += '''
+ and `tabCommunication`.creation > {0}
+ '''.format(after)
if doctype=='User':
- conditions+= " and not (reference_doctype='User' and communication_type='Communication')"
+ conditions += '''
+ and not (`tabCommunication`.reference_doctype='User' and `tabCommunication`.communication_type='Communication')
+ '''
- communications = frappe.db.sql("""select {fields}
+ communications = frappe.db.sql('''
+ select distinct {fields}
from `tabCommunication`
+ inner join `tabDynamic Link`
+ on `tabCommunication`.name=`tabDynamic Link`.parent
where {conditions} {group_by}
- order by creation desc LIMIT %(limit)s OFFSET %(start)s""".format(
- fields = fields, conditions=conditions, group_by=group_by or ""),
- { "doctype": doctype, "name": name, "start": frappe.utils.cint(start), "limit": limit },
- as_dict=as_dict)
+ order by `tabCommunication`.creation desc
+ limit %(limit)s offset %(start)s'''.format(fields = fields, conditions=conditions, group_by=group_by or ""),{
+ "doctype": doctype,
+ "name": name,
+ "start": frappe.utils.cint(start),
+ "limit": limit
+ }, as_dict=as_dict)
return communications
@@ -218,21 +232,6 @@ def run_onload(doc):
doc.set("__onload", frappe._dict())
doc.run_method("onload")
-def get_feedback_rating(doctype, docname):
- """ get and return the latest feedback rating if available """
-
- rating= frappe.get_all("Communication", filters={
- "reference_doctype": doctype,
- "reference_name": docname,
- "communication_type": "Feedback"
- }, fields=["rating"], order_by="creation desc", as_list=True)
-
- if not rating:
- return 0
- else:
- return rating[0][0]
-
-
def get_view_logs(doctype, docname):
""" get and return the latest view logs if available """
logs = []
@@ -244,4 +243,4 @@ def get_view_logs(doctype, docname):
if view_logs:
logs = view_logs
- return logs
+ return logs
\ No newline at end of file
diff --git a/frappe/desk/form/save.py b/frappe/desk/form/save.py
index 1e07f10ba7..694b44b907 100644
--- a/frappe/desk/form/save.py
+++ b/frappe/desk/form/save.py
@@ -27,11 +27,8 @@ def savedocs(doc, action):
# update recent documents
run_onload(doc)
- frappe.get_user().update_recent(doc.doctype, doc.name)
send_updated_docs(doc)
except Exception:
- if not frappe.local.message_log:
- frappe.msgprint(frappe._('Did not save'))
frappe.errprint(frappe.utils.get_traceback())
raise
diff --git a/frappe/desk/link_preview.py b/frappe/desk/link_preview.py
new file mode 100644
index 0000000000..f8252f20bc
--- /dev/null
+++ b/frappe/desk/link_preview.py
@@ -0,0 +1,28 @@
+import frappe
+from frappe.model import no_value_fields
+import json
+
+@frappe.whitelist()
+def get_preview_data(doctype, docname, fields):
+ fields = json.loads(fields)
+ preview_fields = [field['name'] for field in fields if field['type'] not in no_value_fields]
+ preview_fields.append(frappe.get_meta(doctype).get_title_field())
+ if 'name' not in fields:
+ preview_fields.append('name')
+ preview_fields.append(frappe.get_meta(doctype).image_field)
+
+ preview_data = frappe.get_list(doctype, filters={
+ 'name': docname
+ }, fields=preview_fields, limit=1)
+ if preview_data:
+ preview_data = preview_data[0]
+
+ preview_data = {k: v for k, v in preview_data.items() if v is not None}
+ for k,v in preview_data.items():
+ if frappe.get_meta(doctype).has_field(k):
+ preview_data[k] = frappe.format(v,frappe.get_meta(doctype).get_field(k).fieldtype)
+
+ if not preview_data:
+ return None
+ return preview_data
+
diff --git a/frappe/desk/moduleview.py b/frappe/desk/moduleview.py
index a9a460b124..ccde3aad40 100644
--- a/frappe/desk/moduleview.py
+++ b/frappe/desk/moduleview.py
@@ -383,7 +383,7 @@ def get_report_list(module, is_standard="No"):
out.append({
"type": "report",
"doctype": r.ref_doctype,
- "is_query_report": 1 if r.report_type in ("Query Report", "Script Report") else 0,
+ "is_query_report": 1 if r.report_type in ("Query Report", "Script Report", "Custom Report") else 0,
"label": _(r.name),
"name": r.name
})
diff --git a/frappe/desk/page/activity/activity.py b/frappe/desk/page/activity/activity.py
index e25c94d0e5..31ade42e7c 100644
--- a/frappe/desk/page/activity/activity.py
+++ b/frappe/desk/page/activity/activity.py
@@ -38,7 +38,8 @@ def get_feed(start, page_length):
{match_conditions_comment}
) X
order by X.creation DESC
- limit %(start)s, %(page_length)s"""
+ LIMIT %(page_length)s
+ OFFSET %(start)s"""
.format(match_conditions_comment = match_conditions_comment,
match_conditions_communication = match_conditions_communication), {
"user": frappe.session.user,
@@ -55,4 +56,4 @@ def get_heatmap_data():
where
date(creation) > subdate(curdate(), interval 1 year)
group by date(creation)
- order by creation asc"""))
\ No newline at end of file
+ order by creation asc"""))
diff --git a/frappe/desk/page/setup_wizard/setup_wizard.py b/frappe/desk/page/setup_wizard/setup_wizard.py
index cf8f5f502b..a18d4df9c4 100755
--- a/frappe/desk/page/setup_wizard/setup_wizard.py
+++ b/frappe/desk/page/setup_wizard/setup_wizard.py
@@ -389,7 +389,7 @@ def make_records(records, debug=False):
# pass DuplicateEntryError and continue
if e.args and e.args[0]==doc.doctype and e.args[1]==doc.name:
# make sure DuplicateEntryError is for the exact same doc and not a related doc
- pass
+ frappe.clear_messages()
else:
raise
diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py
index 11596d7058..0890e2ad7a 100644
--- a/frappe/desk/query_report.py
+++ b/frappe/desk/query_report.py
@@ -132,6 +132,8 @@ def background_enqueue_run(report_name, filters=None, user=None):
})
track_instance.insert(ignore_permissions=True)
frappe.db.commit()
+ track_instance.enqueue_report()
+
return {
"name": track_instance.name,
"redirect_url": get_url_to_form("Prepared Report", track_instance.name)
@@ -224,7 +226,7 @@ def add_data_to_custom_columns(columns, result):
fieldname = column['fieldname']
key = (column['doctype'], fieldname)
link_field = column['link_field']
- row[fieldname] = custom_fields_data.get(key, {}).get(row[link_field])
+ row[fieldname] = custom_fields_data.get(key, {}).get(row.get(link_field))
return data
@@ -280,6 +282,10 @@ def export_query():
filters = json.loads(data["filters"])
if isinstance(data.get("report_name"), string_types):
report_name = data["report_name"]
+ frappe.permissions.can_export(
+ frappe.get_cached_value('Report', report_name, 'ref_doctype'),
+ raise_exception=True
+ )
if isinstance(data.get("file_format_type"), string_types):
file_format_type = data["file_format_type"]
diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py
index 42409867fb..5ed4dc730b 100644
--- a/frappe/desk/reportview.py
+++ b/frappe/desk/reportview.py
@@ -108,7 +108,7 @@ def save_report():
d.report_type = "Report Builder"
d.json = data['json']
frappe.get_doc(d).save()
- frappe.msgprint(_("{0} is saved").format(d.name))
+ frappe.msgprint(_("{0} is saved").format(d.name), alert=True)
return d.name
@frappe.whitelist()
diff --git a/frappe/email/doctype/auto_email_report/auto_email_report.js b/frappe/email/doctype/auto_email_report/auto_email_report.js
index ba8ab37a99..fab5bd3a8a 100644
--- a/frappe/email/doctype/auto_email_report/auto_email_report.js
+++ b/frappe/email/doctype/auto_email_report/auto_email_report.js
@@ -54,9 +54,9 @@ frappe.ui.form.on('Auto Email Report', {
show_filters: function(frm) {
var wrapper = $(frm.get_field('filters_display').wrapper);
wrapper.empty();
- if(frm.doc.report_type !== 'Report Builder'
+ if(frm.doc.report_type === 'Custom Report' || (frm.doc.report_type !== 'Report Builder'
&& frappe.query_reports[frm.doc.report]
- && frappe.query_reports[frm.doc.report].filters) {
+ && frappe.query_reports[frm.doc.report].filters)) {
// make a table to show filters
var table = $('\
@@ -65,7 +65,17 @@ frappe.ui.form.on('Auto Email Report', {
$('' + __("Click table to edit") + '
').appendTo(wrapper);
var filters = JSON.parse(frm.doc.filters || '{}');
- var report_filters = frappe.query_reports[frm.doc.report].filters;
+
+ let report_filters;
+
+ if (frm.doc.report_type === 'Custom Report'
+ && frappe.query_reports[frm.doc.reference_report]
+ && frappe.query_reports[frm.doc.reference_report].filters) {
+ report_filters = frappe.query_reports[frm.doc.reference_report].filters;
+ } else {
+ report_filters = frappe.query_reports[frm.doc.report].filters;
+ }
+
if(report_filters && report_filters.length > 0) {
frm.set_value('filter_meta', JSON.stringify(report_filters));
}
@@ -99,6 +109,14 @@ frappe.ui.form.on('Auto Email Report', {
dialog.show();
dialog.set_values(filters);
})
+
+ // populate dynamic date field selection
+ let date_fields = report_filters
+ .filter(df => df.fieldtype === 'Date')
+ .map(df => ({ label: df.label, value: df.fieldname }));
+ frm.set_df_property('from_date_field', 'options', date_fields);
+ frm.set_df_property('to_date_field', 'options', date_fields);
+ frm.toggle_display('dynamic_report_filters_section', date_fields.length > 0);
}
}
});
diff --git a/frappe/email/doctype/auto_email_report/auto_email_report.json b/frappe/email/doctype/auto_email_report/auto_email_report.json
index f04f34cdba..4fbbe4e58e 100644
--- a/frappe/email/doctype/auto_email_report/auto_email_report.json
+++ b/frappe/email/doctype/auto_email_report/auto_email_report.json
@@ -1,771 +1,237 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 1,
- "autoname": "",
- "beta": 0,
- "creation": "2016-09-01 01:34:34.985457",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "allow_rename": 1,
+ "creation": "2016-09-01 01:34:34.985457",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "report",
+ "user",
+ "enabled",
+ "column_break_4",
+ "report_type",
+ "reference_report",
+ "filter_data",
+ "send_if_data",
+ "data_modified_till",
+ "no_of_rows",
+ "report_filters",
+ "filters_display",
+ "filters",
+ "filter_meta",
+ "dynamic_report_filters_section",
+ "from_date_field",
+ "to_date_field",
+ "column_break_17",
+ "dynamic_date_period",
+ "email_settings",
+ "email_to",
+ "day_of_week",
+ "column_break_13",
+ "frequency",
+ "format",
+ "section_break_15",
+ "description"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "report",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Report",
- "length": 0,
- "no_copy": 0,
- "options": "Report",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "report",
+ "fieldtype": "Link",
+ "label": "Report",
+ "options": "Report",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "User",
- "fieldname": "user",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Based on Permissions For User",
- "length": 0,
- "no_copy": 0,
- "options": "User",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "User",
+ "fieldname": "user",
+ "fieldtype": "Link",
+ "label": "Based on Permissions For User",
+ "options": "User",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fieldname": "enabled",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Enabled",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "1",
+ "fieldname": "enabled",
+ "fieldtype": "Check",
+ "label": "Enabled"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "report.report_type",
- "fieldname": "report_type",
- "fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Report Type",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "report.report_type",
+ "fieldname": "report_type",
+ "fieldtype": "Read Only",
+ "label": "Report Type"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "filter_data",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Filter Data",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "filter_data",
+ "fieldtype": "Section Break",
+ "label": "Filter Data"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fieldname": "send_if_data",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Send only if there is any data",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "1",
+ "fieldname": "send_if_data",
+ "fieldtype": "Check",
+ "label": "Send only if there is any data"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "depends_on": "eval:doc.report_type=='Report Builder'",
- "description": "Zero means send records updated at anytime",
- "fieldname": "data_modified_till",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Only Send Records Updated in Last X Hours",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.report_type=='Report Builder'",
+ "description": "Zero means send records updated at anytime",
+ "fieldname": "data_modified_till",
+ "fieldtype": "Int",
+ "label": "Only Send Records Updated in Last X Hours"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "100",
- "description": "",
- "fieldname": "no_of_rows",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "No of Rows (Max 500)",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "100",
+ "fieldname": "no_of_rows",
+ "fieldtype": "Int",
+ "label": "No of Rows (Max 500)"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "depends_on": "eval:doc.report_type !== 'Report Builder'",
- "fieldname": "report_filters",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Report Filters",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "depends_on": "eval:doc.report_type !== 'Report Builder'",
+ "fieldname": "report_filters",
+ "fieldtype": "Section Break",
+ "label": "Report Filters"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "filters_display",
- "fieldtype": "HTML",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Filters Display",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "filters_display",
+ "fieldtype": "HTML",
+ "label": "Filters Display"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "filters",
- "fieldtype": "Text",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Filters",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "filters",
+ "fieldtype": "Text",
+ "hidden": 1,
+ "label": "Filters"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "filter_meta",
- "fieldtype": "Text",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Filter Meta",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "filter_meta",
+ "fieldtype": "Text",
+ "hidden": 1,
+ "label": "Filter Meta",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "email_settings",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Email Settings",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "depends_on": "eval:doc.report_type !== 'Report Builder'",
+ "fieldname": "dynamic_report_filters_section",
+ "fieldtype": "Section Break",
+ "label": "Dynamic Report Filters"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "email_to",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Email To",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "from_date_field",
+ "fieldtype": "Select",
+ "label": "From Date Field"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Monday",
- "depends_on": "eval:doc.frequency=='Weekly'",
- "fieldname": "day_of_week",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Day of Week",
- "length": 0,
- "no_copy": 0,
- "options": "Monday\nTuesday\nWednesday\nThursday\nFriday\nSaturday\nSunday",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "to_date_field",
+ "fieldtype": "Select",
+ "label": "To Date Field"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_13",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_17",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "frequency",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Frequency",
- "length": 0,
- "no_copy": 0,
- "options": "Daily\nWeekdays\nWeekly\nMonthly",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "dynamic_date_period",
+ "fieldtype": "Select",
+ "label": "Period",
+ "options": "\nDaily\nWeekly\nMonthly\nQuarterly\nHalf Yearly\nYearly"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "format",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Format",
- "length": 0,
- "no_copy": 0,
- "options": "HTML\nXLSX\nCSV",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "email_settings",
+ "fieldtype": "Section Break",
+ "label": "Email Settings"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "section_break_15",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Message",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "email_to",
+ "fieldtype": "Small Text",
+ "label": "Email To",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Message",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "default": "Monday",
+ "depends_on": "eval:doc.frequency=='Weekly'",
+ "fieldname": "day_of_week",
+ "fieldtype": "Select",
+ "label": "Day of Week",
+ "options": "Monday\nTuesday\nWednesday\nThursday\nFriday\nSaturday\nSunday"
+ },
+ {
+ "fieldname": "column_break_13",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "frequency",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Frequency",
+ "options": "Daily\nWeekdays\nWeekly\nMonthly",
+ "reqd": 1
+ },
+ {
+ "fieldname": "format",
+ "fieldtype": "Select",
+ "label": "Format",
+ "options": "HTML\nXLSX\nCSV",
+ "reqd": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "section_break_15",
+ "fieldtype": "Section Break",
+ "label": "Message"
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Text Editor",
+ "label": "Message"
+ },
+ {
+ "fetch_from": "report.reference_report",
+ "fieldname": "reference_report",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Reference Report",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-11-13 01:59:17.816718",
- "modified_by": "Administrator",
- "module": "Email",
- "name": "Auto Email Report",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "modified": "2019-05-09 22:38:27.570890",
+ "modified_by": "Administrator",
+ "module": "Email",
+ "name": "Auto Email Report",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Report Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Report Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/frappe/email/doctype/auto_email_report/auto_email_report.py b/frappe/email/doctype/auto_email_report/auto_email_report.py
index c0a9c71d34..b06d3f7dfe 100644
--- a/frappe/email/doctype/auto_email_report/auto_email_report.py
+++ b/frappe/email/doctype/auto_email_report/auto_email_report.py
@@ -5,14 +5,13 @@
from __future__ import unicode_literals
import calendar
-import json
from datetime import timedelta
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import (format_time, get_link_to_form, get_url_to_report,
- global_date_format, now, now_datetime, validate_email_address)
+ global_date_format, now, now_datetime, validate_email_address, today, add_to_date)
from frappe.utils.csvutils import to_csv
from frappe.utils.xlsxutils import make_xlsx
@@ -58,10 +57,14 @@ class AutoEmailReport(Document):
'''Returns file in for the report in given format'''
report = frappe.get_doc('Report', self.report)
+ self.filters = frappe.parse_json(self.filters) if self.filters else {}
+
if self.report_type=='Report Builder' and self.data_modified_till:
- self.filters = json.loads(self.filters) if self.filters else {}
self.filters['modified'] = ('>', now_datetime() - timedelta(hours=self.data_modified_till))
+ if self.report_type != 'Report Builder' and self.dynamic_date_filters_set():
+ self.prepare_dynamic_filters()
+
columns, data = report.get_data(limit=self.no_of_rows or 100, user = self.user,
filters = self.filters, as_dict=True)
@@ -121,6 +124,24 @@ class AutoEmailReport(Document):
def get_file_name(self):
return "{0}.{1}".format(self.report.replace(" ", "-").replace("/", "-"), self.format.lower())
+ def prepare_dynamic_filters(self):
+ self.filters = frappe.parse_json(self.filters)
+
+ to_date = today()
+ from_date_value = {
+ 'Daily': ('days', -1),
+ 'Weekly': ('weeks', -1),
+ 'Monthly': ('months', -1),
+ 'Quarterly': ('months', -3),
+ 'Half Yearly': ('months', -6),
+ 'Yearly': ('years', -1)
+ }[self.dynamic_date_period]
+
+ from_date = add_to_date(to_date, **{from_date_value[0]: from_date_value[1]})
+
+ self.filters[self.from_date_field] = from_date
+ self.filters[self.to_date_field] = to_date
+
def send(self):
if self.filter_meta and not self.filters:
frappe.throw(_("Please set filters value in Report Filter table."))
@@ -150,6 +171,9 @@ class AutoEmailReport(Document):
reference_name = self.name
)
+ def dynamic_date_filters_set(self):
+ return self.dynamic_date_period and self.from_date_field and self.to_date_field
+
@frappe.whitelist()
def download(name):
'''Download report locally'''
diff --git a/frappe/email/doctype/auto_email_report/test_auto_email_report.py b/frappe/email/doctype/auto_email_report/test_auto_email_report.py
index 0595d9a43d..651fee9e51 100644
--- a/frappe/email/doctype/auto_email_report/test_auto_email_report.py
+++ b/frappe/email/doctype/auto_email_report/test_auto_email_report.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import unittest, json
-from frappe.utils import get_link_to_form
+from frappe.utils import get_link_to_form, today, add_to_date
# test_records = frappe.get_test_records('Auto Email Report')
@@ -13,17 +13,7 @@ class TestAutoEmailReport(unittest.TestCase):
def test_auto_email(self):
frappe.delete_doc('Auto Email Report', 'Permitted Documents For User')
- auto_email_report = frappe.get_doc(dict(
- doctype='Auto Email Report',
- report='Permitted Documents For User',
- report_type='Script Report',
- user='Administrator',
- enabled=1,
- email_to='test@example.com',
- format='HTML',
- frequency='Daily',
- filters=json.dumps(dict(user='Administrator', doctype='DocType'))
- )).insert()
+ auto_email_report = get_auto_email_report()
data = auto_email_report.get_report_content()
@@ -38,3 +28,34 @@ class TestAutoEmailReport(unittest.TestCase):
data = auto_email_report.get_report_content()
+
+ def test_dynamic_date_filters(self):
+ auto_email_report = get_auto_email_report()
+
+ auto_email_report.dynamic_date_period = 'Weekly'
+ auto_email_report.from_date_field = 'from_date'
+ auto_email_report.to_date_field = 'to_date'
+
+ auto_email_report.prepare_dynamic_filters()
+
+ self.assertEqual(auto_email_report.filters['from_date'], add_to_date(today(), weeks=-1))
+ self.assertEqual(auto_email_report.filters['to_date'], today())
+
+
+def get_auto_email_report():
+ if not frappe.db.exists('Auto Email Report', 'Permitted Documents For User'):
+ auto_email_report = frappe.get_doc(dict(
+ doctype='Auto Email Report',
+ report='Permitted Documents For User',
+ report_type='Script Report',
+ user='Administrator',
+ enabled=1,
+ email_to='test@example.com',
+ format='HTML',
+ frequency='Daily',
+ filters=json.dumps(dict(user='Administrator', doctype='DocType'))
+ )).insert()
+ else:
+ auto_email_report = frappe.get_doc('Auto Email Report', 'Permitted Documents For User')
+
+ return auto_email_report
\ No newline at end of file
diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py
index b1ad7ede99..6ef94883f7 100755
--- a/frappe/email/doctype/email_account/email_account.py
+++ b/frappe/email/doctype/email_account/email_account.py
@@ -387,7 +387,7 @@ class EmailAccount(Document):
communication._seen = json.dumps(users)
communication.flags.in_receive = True
- communication.insert(ignore_permissions = 1)
+ communication.insert(ignore_permissions=True)
# save attachments
communication._attachments = email.save_attachments_in_doc(communication)
@@ -470,7 +470,7 @@ class EmailAccount(Document):
parent = frappe.db.get_all(self.append_to, filters={
self.sender_field: email.from_email,
self.subject_field: ("like", "%{0}%".format(subject)),
- "creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT))
+ "creation": (">", (get_datetime() - relativedelta(days=60)).strftime(DATE_FORMAT))
}, fields="name")
# match only subject field
@@ -479,7 +479,7 @@ class EmailAccount(Document):
if not parent and len(subject) > 10 and is_system_user(email.from_email):
parent = frappe.db.get_all(self.append_to, filters={
self.subject_field: ("like", "%{0}%".format(subject)),
- "creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT))
+ "creation": (">", (get_datetime() - relativedelta(days=60)).strftime(DATE_FORMAT))
}, fields="name")
if parent:
diff --git a/frappe/email/doctype/email_account/test_email_account.py b/frappe/email/doctype/email_account/test_email_account.py
index f098a8b205..ac16f12477 100644
--- a/frappe/email/doctype/email_account/test_email_account.py
+++ b/frappe/email/doctype/email_account/test_email_account.py
@@ -26,7 +26,7 @@ class TestEmailAccount(unittest.TestCase):
email_account.db_set("enable_incoming", 0)
def test_incoming(self):
- frappe.db.sql("delete from tabCommunication where sender='test_sender@example.com'")
+ cleanup("test_sender@example.com")
with open(os.path.join(os.path.dirname(__file__), "test_mails", "incoming-1.raw"), "r") as f:
test_mails = [f.read()]
@@ -52,7 +52,8 @@ class TestEmailAccount(unittest.TestCase):
"reference_name": comm.reference_name, "status":"Not Sent"}))
def test_incoming_with_attach(self):
- frappe.db.sql("DELETE FROM `tabCommunication` WHERE sender='test_sender@example.com'")
+ cleanup("test_sender@example.com")
+
existing_file = frappe.get_doc({'doctype': 'File', 'file_name': 'erpnext-conf-14.png'})
frappe.delete_doc("File", existing_file.name)
@@ -75,7 +76,7 @@ class TestEmailAccount(unittest.TestCase):
def test_incoming_attached_email_from_outlook_plain_text_only(self):
- frappe.db.sql("delete from tabCommunication where sender='test_sender@example.com'")
+ cleanup("test_sender@example.com")
with open(os.path.join(os.path.dirname(__file__), "test_mails", "incoming-3.raw"), "r") as f:
test_mails = [f.read()]
@@ -88,7 +89,7 @@ class TestEmailAccount(unittest.TestCase):
self.assertTrue("This is an e-mail message sent automatically by Microsoft Outlook while" in comm.content)
def test_incoming_attached_email_from_outlook_layers(self):
- frappe.db.sql("delete from tabCommunication where sender='test_sender@example.com'")
+ cleanup("test_sender@example.com")
with open(os.path.join(os.path.dirname(__file__), "test_mails", "incoming-4.raw"), "r") as f:
test_mails = [f.read()]
@@ -123,8 +124,7 @@ class TestEmailAccount(unittest.TestCase):
self.assertTrue("test-mail-002" in sent_mail.get("Subject"))
def test_threading(self):
- frappe.db.sql("""delete from tabCommunication
- where sender in ('test_sender@example.com', 'test@example.com')""")
+ cleanup(["in", ['test_sender@example.com', 'test@example.com']])
# send
sent_name = make(subject = "Test", content="test content",
@@ -149,8 +149,7 @@ class TestEmailAccount(unittest.TestCase):
self.assertEqual(comm.reference_name, sent.reference_name)
def test_threading_by_subject(self):
- frappe.db.sql("""delete from tabCommunication
- where sender in ('test_sender@example.com', 'test@example.com')""")
+ cleanup(["in", ['test_sender@example.com', 'test@example.com']])
with open(os.path.join(os.path.dirname(__file__), "test_mails", "reply-2.raw"), "r") as f:
test_mails = [f.read()]
@@ -170,7 +169,7 @@ class TestEmailAccount(unittest.TestCase):
self.assertEqual(comm_list[0].reference_name, comm_list[1].reference_name)
def test_threading_by_message_id(self):
- frappe.db.sql("""delete from tabCommunication""")
+ cleanup()
frappe.db.sql("""delete from `tabEmail Queue`""")
# reference document for testing
@@ -196,3 +195,13 @@ class TestEmailAccount(unittest.TestCase):
# check if threaded correctly
self.assertEqual(comm_list[0].reference_doctype, event.doctype)
self.assertEqual(comm_list[0].reference_name, event.name)
+
+def cleanup(sender=None):
+ filters = {}
+ if sender:
+ filters.update({"sender": sender})
+
+ names = frappe.get_list("Communication", filters=filters, fields=["name"])
+ for name in names:
+ frappe.delete_doc_if_exists("Communication", name.name)
+ frappe.delete_doc_if_exists("Dynamic Link", {"parent": name.name})
\ No newline at end of file
diff --git a/frappe/email/inbox.py b/frappe/email/inbox.py
index 9df4218d71..9d15b387e3 100644
--- a/frappe/email/inbox.py
+++ b/frappe/email/inbox.py
@@ -118,67 +118,4 @@ def link_communication_to_document(doc, reference_doctype, reference_name, ignor
doc.reference_doctype = reference_doctype
doc.reference_name = reference_name
doc.status = "Linked"
- doc.save(ignore_permissions=True)
-
-@frappe.whitelist()
-def make_issue_from_communication(communication, ignore_communication_links=False):
- """ raise a issue from email """
-
- doc = frappe.get_doc("Communication", communication)
- issue = frappe.get_doc({
- "doctype": "Issue",
- "subject": doc.subject,
- "communication_medium": doc.communication_medium,
- "raised_by": doc.sender or "",
- "raised_by_phone": doc.phone_no or ""
- }).insert(ignore_permissions=True)
-
- link_communication_to_document(doc, "Issue", issue.name, ignore_communication_links)
-
- return issue.name
-
-@frappe.whitelist()
-def make_lead_from_communication(communication, ignore_communication_links=False):
- """ raise a issue from email """
-
- doc = frappe.get_doc("Communication", communication)
- lead_name = None
- if doc.sender:
- lead_name = frappe.db.get_value("Lead", {"email_id": doc.sender})
- if not lead_name and doc.mobile_no:
- lead_name = frappe.db.get_value("Lead", {"mobile_no": doc.phone_no})
- if not lead_name:
- lead = frappe.get_doc({
- "doctype": "Lead",
- "lead_name": doc.sender_full_name,
- "email_id": doc.sender,
- "mobile_no": doc.phone_no
- })
- lead.flags.ignore_mandatory = True
- lead.flags.ignore_permissions = True
- lead.insert()
-
- lead_name = lead.name
-
- link_communication_to_document(doc, "Lead", lead_name, ignore_communication_links)
- return lead_name
-
-@frappe.whitelist()
-def make_opportunity_from_communication(communication, ignore_communication_links=False):
- doc = frappe.get_doc("Communication", communication)
-
- lead = doc.reference_name if doc.reference_doctype == "Lead" else None
- if not lead:
- lead = make_lead_from_communication(communication, ignore_communication_links=True)
-
- enquiry_from = "Lead"
-
- opportunity = frappe.get_doc({
- "doctype": "Opportunity",
- "enquiry_from": enquiry_from,
- "lead": lead
- }).insert(ignore_permissions=True)
-
- link_communication_to_document(doc, "Opportunity", opportunity.name, ignore_communication_links)
-
- return opportunity.name
+ doc.save(ignore_permissions=True)
\ No newline at end of file
diff --git a/frappe/geo/country_info.json b/frappe/geo/country_info.json
index bdd6414730..7a6ba56929 100644
--- a/frappe/geo/country_info.json
+++ b/frappe/geo/country_info.json
@@ -2330,6 +2330,7 @@
},
"Suriname": {
"code": "sr",
+ "currency": "SRD",
"currency_fraction": "Cent",
"currency_fraction_units": 100,
"currency_symbol": "$",
diff --git a/frappe/handler.py b/frappe/handler.py
index 7a040871ad..71601028f1 100755
--- a/frappe/handler.py
+++ b/frappe/handler.py
@@ -8,6 +8,7 @@ import frappe.utils
import frappe.sessions
import frappe.desk.form.run_method
from frappe.utils.response import build_response
+from frappe.utils import cint
from werkzeug.wrappers import Response
from six import string_types
@@ -138,6 +139,46 @@ def uploadfile():
return ret
+@frappe.whitelist()
+def upload_file():
+ files = frappe.request.files
+ is_private = frappe.form_dict.is_private
+ doctype = frappe.form_dict.doctype
+ docname = frappe.form_dict.docname
+ fieldname = frappe.form_dict.fieldname
+ file_url = frappe.form_dict.file_url
+ folder = frappe.form_dict.folder or 'Home'
+ method = frappe.form_dict.method
+ content = None
+ filename = None
+
+ if 'file' in files:
+ file = files['file']
+ content = file.stream.read()
+ filename = file.filename
+
+ frappe.local.uploaded_file = content
+ frappe.local.uploaded_filename = filename
+
+ if method:
+ method = frappe.get_attr(method)
+ is_whitelisted(method)
+ return method()
+ else:
+ ret = frappe.get_doc({
+ "doctype": "File",
+ "attached_to_doctype": doctype,
+ "attached_to_name": docname,
+ "attached_to_field": fieldname,
+ "folder": folder,
+ "file_name": filename,
+ "file_url": file_url,
+ "is_private": cint(is_private),
+ "content": content
+ })
+ ret.save()
+ return ret
+
def get_attr(cmd):
"""get method object from cmd"""
diff --git a/frappe/hooks.py b/frappe/hooks.py
index 9865f6f4ac..52e2e1e4a0 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -118,7 +118,7 @@ doc_events = {
"frappe.core.doctype.activity_log.feed.update_feed",
"frappe.workflow.doctype.workflow_action.workflow_action.process_workflow_actions",
"frappe.automation.doctype.assignment_rule.assignment_rule.apply",
- "frappe.social.doctype.energy_point_rule.energy_point_rule.process_energy_points"
+ "frappe.automation.doctype.milestone_tracker.milestone_tracker.evaluate_milestone"
],
"after_rename": "frappe.desk.notifications.clear_doctype_notifications",
"on_cancel": [
@@ -130,8 +130,8 @@ doc_events = {
"frappe.workflow.doctype.workflow_action.workflow_action.process_workflow_actions"
],
"on_change": [
- "frappe.core.doctype.feedback_trigger.feedback_trigger.trigger_feedback_request"
- ]
+ "frappe.social.doctype.energy_point_rule.energy_point_rule.process_energy_points"
+ ],
},
"Email Group Member": {
"validate": "frappe.email.doctype.email_group.email_group.restrict_email_group"
@@ -156,6 +156,7 @@ scheduler_events = {
"frappe.utils.error.collect_error_snapshots",
"frappe.desk.page.backups.backups.delete_downloadable_backups",
"frappe.limits.update_space_usage",
+ "frappe.limits.update_site_usage",
"frappe.desk.doctype.auto_repeat.auto_repeat.make_auto_repeat_entry",
"frappe.deferred_insert.save_to_db",
"frappe.desk.form.document_follow.send_hourly_updates"
@@ -171,7 +172,6 @@ scheduler_events = {
"frappe.utils.scheduler.disable_scheduler_on_expiry",
"frappe.utils.scheduler.restrict_scheduler_events_if_dormant",
"frappe.email.doctype.auto_email_report.auto_email_report.send_daily",
- "frappe.core.doctype.feedback_request.feedback_request.delete_feedback_request",
"frappe.core.doctype.activity_log.activity_log.clear_authentication_logs",
"frappe.website.doctype.personal_data_deletion_request.personal_data_deletion_request.remove_unverified_record",
"frappe.desk.form.document_follow.send_daily_updates",
@@ -284,4 +284,4 @@ user_privacy_documents = [
'applies_to_website_user': 1
},
-]
\ No newline at end of file
+]
diff --git a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js
index d046709230..ddaa740afd 100644
--- a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js
+++ b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js
@@ -3,6 +3,39 @@
frappe.ui.form.on('GSuite Templates', {
refresh: function(frm) {
-
- }
+ if (frm.is_new()) {
+ // if doc is new, get all options immediately
+ frm.trigger('set_available_docs');
+ frm.trigger('set_available_folders');
+ }
+ },
+ set_available_docs: function(frm) {
+ frappe.call({
+ // get documents from Google Drive
+ method: 'frappe.integrations.doctype.gsuite_templates.gsuite_templates.get_gdrive_docs',
+ callback: function(res) {
+ // set available documents as options
+ set_gsuite_template_options(frm, 'template_id', res);
+ }
+ });
+ },
+ set_available_folders: function(frm) {
+ frappe.call({
+ // get folders from Google Drive
+ method: 'frappe.integrations.doctype.gsuite_templates.gsuite_templates.get_gdrive_folders',
+ callback: function(res) {
+ // set available folders as options
+ set_gsuite_template_options(frm, 'destination_id', res);
+ }
+ });
+ },
});
+
+const set_gsuite_template_options = function(frm, field, data) {
+ var options = [];
+ (data.message || []).forEach(function(row){
+ options.push({'value': row.id, 'label': row.name});
+ });
+ frm.set_df_property(field, 'options', options);
+};
+
diff --git a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.json b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.json
index 6543e8847e..e0e047a671 100644
--- a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.json
+++ b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@@ -15,10 +16,12 @@
"fields": [
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "template_name",
"fieldtype": "Data",
"hidden": 0,
@@ -26,7 +29,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
"in_standard_filter": 0,
"label": "Template Name",
"length": 0,
@@ -41,14 +44,17 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "unique": 0
+ "translatable": 0,
+ "unique": 1
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "related_doctype",
"fieldtype": "Link",
"hidden": 0,
@@ -72,22 +78,25 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "template_id",
- "fieldtype": "Data",
+ "fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
"in_standard_filter": 0,
"label": "Template ID",
"length": 0,
@@ -101,16 +110,19 @@
"report_hide": 0,
"reqd": 1,
"search_index": 0,
- "set_only_once": 0,
+ "set_only_once": 1,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "New Document for {name} ",
+ "fetch_if_empty": 0,
"fieldname": "document_name",
"fieldtype": "Data",
"hidden": 0,
@@ -118,7 +130,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
"in_standard_filter": 0,
"label": "Document Name",
"length": 0,
@@ -133,16 +145,19 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "destination_id",
- "fieldtype": "Data",
+ "fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -162,21 +177,20 @@
"report_hide": 0,
"reqd": 0,
"search_index": 0,
- "set_only_once": 0,
+ "set_only_once": 1,
+ "translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
- "hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
- "image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-05-12 16:50:08.074882",
+ "modified": "2019-04-14 00:13:49.999149",
"modified_by": "Administrator",
"module": "Integrations",
"name": "GSuite Templates",
@@ -185,7 +199,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -206,10 +219,10 @@
],
"quick_entry": 0,
"read_only": 0,
- "read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
- "track_seen": 0
+ "track_seen": 0,
+ "track_views": 0
}
\ No newline at end of file
diff --git a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.py b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.py
index ad9f8145de..66028a13d4 100644
--- a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.py
+++ b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.py
@@ -3,6 +3,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+import requests
import frappe
from frappe import _
from frappe.model.document import Document
@@ -48,3 +49,45 @@ def create_gsuite_doc(doctype, docname, gs_template=None):
"is_private": _file.is_private,
"comment": comment.as_dict() if comment else {}
}
+
+@frappe.whitelist()
+def get_gdrive_docs():
+ """ Return a list of Google Docs files in Google Drive """
+ return get_gdrive_files('application/vnd.google-apps.document')
+
+@frappe.whitelist()
+def get_gdrive_folders():
+ """ Return a list of folders in Google Drive """
+ return get_gdrive_files('application/vnd.google-apps.folder')
+
+def get_gdrive_files(mime_type):
+ """ Get a list of files of the specified mime_type from Google Drive
+
+ returns [
+ {
+ "kind": "drive#file",
+ "id": "sf_lk-U6lYhVvdgsdf98cvkbj87rl6piFtnLEN9oNsrg",
+ "name": "My File Name",
+ "mimeType": mime_type
+ }
+ ]
+ """
+ settings = frappe.get_single("GSuite Settings")
+ token = settings.get_access_token()
+ url = 'https://www.googleapis.com/drive/v3/files'
+
+ params = {
+ "q": "mimeType='{}'".format(mime_type)
+ }
+
+ headers = {
+ 'Authorization': 'Bearer {}'.format(token),
+ 'Accept': 'application/json'
+ }
+
+ try:
+ response = requests.get(url, params=params, headers=headers)
+ except requests.exceptions.RequestException as err:
+ frappe.throw(err)
+
+ return response.json().get('files')
diff --git a/frappe/integrations/doctype/integration_request/integration_request.json b/frappe/integrations/doctype/integration_request/integration_request.json
index f69668973e..c3123fb574 100644
--- a/frappe/integrations/doctype/integration_request/integration_request.json
+++ b/frappe/integrations/doctype/integration_request/integration_request.json
@@ -1,5 +1,7 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -12,16 +14,20 @@
"engine": "InnoDB",
"fields": [
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "integration_type",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Integration Type",
@@ -38,19 +44,24 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "integration_request_service",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Integration Request Service",
@@ -67,26 +78,31 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Queued",
+ "fetch_if_empty": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Status",
"length": 0,
"no_copy": 0,
- "options": "\nQueued\nAuthorized\nCompleted\nCancelled\nFailed\n",
+ "options": "\nQueued\nAuthorized\nCompleted\nCancelled\nFailed",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -97,19 +113,24 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "data",
"fieldtype": "Code",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Data",
@@ -125,19 +146,24 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "output",
"fieldtype": "Code",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Output",
@@ -153,19 +179,24 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "error",
"fieldtype": "Code",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Error",
@@ -181,19 +212,24 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "reference_doctype",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Reference Doctype",
@@ -210,19 +246,24 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "reference_docname",
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Reference Docname",
@@ -239,20 +280,21 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 1,
-
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-10-09 14:40:00.783063",
+ "modified": "2019-04-25 16:38:21.084580",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Integration Request",
@@ -261,7 +303,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -269,7 +310,6 @@
"export": 1,
"if_owner": 0,
"import": 0,
- "is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@@ -284,9 +324,11 @@
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
+ "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "integration_request_service",
"track_changes": 1,
- "track_seen": 0
+ "track_seen": 0,
+ "track_views": 0
}
\ No newline at end of file
diff --git a/frappe/integrations/oauth2_logins.py b/frappe/integrations/oauth2_logins.py
index 86a90078c6..aecbe3be66 100644
--- a/frappe/integrations/oauth2_logins.py
+++ b/frappe/integrations/oauth2_logins.py
@@ -2,14 +2,16 @@
# MIT License. See license.txt
from __future__ import unicode_literals
+
import frappe
import frappe.utils
-from frappe.utils.oauth import login_via_oauth2, login_via_oauth2_id_token
-import json
+from frappe.utils.oauth import (login_via_oauth2, login_via_oauth2_id_token,
+ oauth_decoder)
+
@frappe.whitelist(allow_guest=True)
def login_via_google(code, state):
- login_via_oauth2("google", code, state, decoder=json.loads)
+ login_via_oauth2("google", code, state, decoder=oauth_decoder)
@frappe.whitelist(allow_guest=True)
def login_via_github(code, state):
@@ -17,20 +19,20 @@ def login_via_github(code, state):
@frappe.whitelist(allow_guest=True)
def login_via_facebook(code, state):
- login_via_oauth2("facebook", code, state, decoder=json.loads)
+ login_via_oauth2("facebook", code, state, decoder=oauth_decoder)
@frappe.whitelist(allow_guest=True)
def login_via_frappe(code, state):
- login_via_oauth2("frappe", code, state, decoder=json.loads)
+ login_via_oauth2("frappe", code, state, decoder=oauth_decoder)
@frappe.whitelist(allow_guest=True)
def login_via_office365(code, state):
- login_via_oauth2_id_token("office_365", code, state, decoder=json.loads)
+ login_via_oauth2_id_token("office_365", code, state, decoder=oauth_decoder)
@frappe.whitelist(allow_guest=True)
def login_via_salesforce(code, state):
- login_via_oauth2("salesforce", code, state, decoder=json.loads)
+ login_via_oauth2("salesforce", code, state, decoder=oauth_decoder)
@frappe.whitelist(allow_guest=True)
def login_via_fairlogin(code, state):
- login_via_oauth2("fairlogin", code, state, decoder=json.loads)
+ login_via_oauth2("fairlogin", code, state, decoder=oauth_decoder)
diff --git a/frappe/limits.py b/frappe/limits.py
index fe800e3fe5..8295de5a34 100755
--- a/frappe/limits.py
+++ b/frappe/limits.py
@@ -5,7 +5,8 @@ from frappe.utils import now_datetime, getdate, flt, cint, get_fullname
from frappe.installer import update_site_config
from frappe.utils.data import formatdate
from frappe.utils.user import get_enabled_system_users, disable_users
-import os, subprocess
+from frappe.utils.__init__ import get_site_info
+import os, subprocess, json
from six.moves.urllib.parse import parse_qsl, urlsplit, urlunsplit, urlencode
from six import string_types
@@ -225,3 +226,8 @@ def get_folder_size(path):
if os.path.exists(path):
return flt(subprocess.check_output(['du', '-ms', path]).split()[0], 2)
+def update_site_usage():
+ data = get_site_info()
+ with open(os.path.join(frappe.get_site_path(), 'site_data.json'), 'w') as outfile:
+ json.dump(data, outfile)
+ outfile.close()
diff --git a/frappe/migrate.py b/frappe/migrate.py
index 4057c99b63..1128f6eff3 100644
--- a/frappe/migrate.py
+++ b/frappe/migrate.py
@@ -3,6 +3,8 @@
from __future__ import unicode_literals
+import json
+import os
import frappe
import frappe.translate
import frappe.modules.patch_handler
@@ -10,9 +12,10 @@ import frappe.model.sync
from frappe.utils.fixtures import sync_fixtures
from frappe.cache_manager import clear_global_cache
from frappe.desk.notifications import clear_notifications
-from frappe.website import render, router
+from frappe.website import render
from frappe.core.doctype.language.language import sync_languages
from frappe.modules.utils import sync_customizations
+from frappe.utils import global_search
def migrate(verbose=True, rebuild_website=False):
'''Migrate all apps to the latest version, will:
@@ -25,39 +28,52 @@ def migrate(verbose=True, rebuild_website=False):
- sync web pages (from /www)
- run after migrate hooks
'''
- frappe.flags.in_migrate = True
- clear_global_cache()
- #run before_migrate hooks
- for app in frappe.get_installed_apps():
- for fn in frappe.get_hooks('before_migrate', app_name=app):
- frappe.get_attr(fn)()
+ touched_tables_file = frappe.get_site_path('touched_tables.json')
+ if os.path.exists(touched_tables_file):
+ os.remove(touched_tables_file)
- # run patches
- frappe.modules.patch_handler.run_all()
- # sync
- frappe.model.sync.sync_all(verbose=verbose)
- frappe.translate.clear_cache()
- sync_fixtures()
- sync_customizations()
- sync_languages()
+ try:
+ frappe.flags.touched_tables = set()
+ frappe.flags.in_migrate = True
- frappe.get_doc('Portal Settings', 'Portal Settings').sync_menu()
+ clear_global_cache()
- # syncs statics
- render.clear_cache()
+ #run before_migrate hooks
+ for app in frappe.get_installed_apps():
+ for fn in frappe.get_hooks('before_migrate', app_name=app):
+ frappe.get_attr(fn)()
- # add static pages to global search
- router.sync_global_search()
+ # run patches
+ frappe.modules.patch_handler.run_all()
+ # sync
+ frappe.model.sync.sync_all(verbose=verbose)
+ frappe.translate.clear_cache()
+ sync_fixtures()
+ sync_customizations()
+ sync_languages()
- #run after_migrate hooks
- for app in frappe.get_installed_apps():
- for fn in frappe.get_hooks('after_migrate', app_name=app):
- frappe.get_attr(fn)()
+ frappe.get_doc('Portal Settings', 'Portal Settings').sync_menu()
- frappe.db.commit()
+ # syncs statics
+ render.clear_cache()
- clear_notifications()
+ # add static pages to global search
+ global_search.update_global_search_for_all_web_pages()
+
+ #run after_migrate hooks
+ for app in frappe.get_installed_apps():
+ for fn in frappe.get_hooks('after_migrate', app_name=app):
+ frappe.get_attr(fn)()
+
+ frappe.db.commit()
+
+ clear_notifications()
+
+ frappe.publish_realtime("version-update")
+ frappe.flags.in_migrate = False
+ finally:
+ with open(touched_tables_file, 'w') as f:
+ json.dump(list(frappe.flags.touched_tables), f, sort_keys=True, indent=4)
+ frappe.flags.touched_tables.clear()
- frappe.publish_realtime("version-update")
- frappe.flags.in_migrate = False
diff --git a/frappe/model/__init__.py b/frappe/model/__init__.py
index 5f804e3c36..3a8868ec2c 100644
--- a/frappe/model/__init__.py
+++ b/frappe/model/__init__.py
@@ -76,27 +76,43 @@ def delete_fields(args_dict, delete=0):
args_dict = { dt: [field names] }
"""
import frappe.utils
- for dt in list(args_dict):
+ for dt in args_dict:
fields = args_dict[dt]
- if not fields: continue
+ if not fields:
+ continue
- frappe.db.sql("""\
+ frappe.db.sql("""
DELETE FROM `tabDocField`
- WHERE parent=%s AND fieldname IN (%s)
- """ % ('%s', ", ".join(['"' + f + '"' for f in fields])), dt)
+ WHERE parent='%s' AND fieldname IN (%s)
+ """ % (dt, ", ".join(["'{}'".format(f) for f in fields])))
- # Delete the data / column only if delete is specified
- if not delete: continue
+ # Delete the data/column only if delete is specified
+ if not delete:
+ continue
if frappe.db.get_value("DocType", dt, "issingle"):
- frappe.db.sql("""\
+ frappe.db.sql("""
DELETE FROM `tabSingles`
- WHERE doctype=%s AND field IN (%s)
- """ % ('%s', ", ".join(['"' + f + '"' for f in fields])), dt)
+ WHERE doctype='%s' AND field IN (%s)
+ """ % (dt, ", ".join(["'{}'".format(f) for f in fields])))
else:
- existing_fields = frappe.db.sql("desc `tab%s`" % dt)
+ existing_fields = frappe.db.multisql({
+ "mariadb": "DESC `tab%s`" % dt,
+ "postgres": """
+ SELECT
+ COLUMN_NAME
+ FROM
+ information_schema.COLUMNS
+ WHERE
+ TABLE_NAME = 'tab%s';
+ """ % dt,
+ })
existing_fields = existing_fields and [e[0] for e in existing_fields] or []
+ fields_need_to_delete = set(fields) & set(existing_fields)
+ if not fields_need_to_delete:
+ continue
query = "ALTER TABLE `tab%s` " % dt + \
- ", ".join(["DROP COLUMN `%s`" % f for f in fields if f in existing_fields])
- frappe.db.commit()
+ ", ".join(["DROP COLUMN `%s`" % f for f in fields_need_to_delete])
frappe.db.sql(query)
+ # commit the results to db
+ frappe.db.commit()
diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py
index 8b03a21a2b..ae4bc07b1a 100644
--- a/frappe/model/base_document.py
+++ b/frappe/model/base_document.py
@@ -197,7 +197,7 @@ class BaseDocument(object):
return value
- def get_valid_dict(self, sanitize=True, convert_dates_to_str=False):
+ def get_valid_dict(self, sanitize=True, convert_dates_to_str=False, ignore_nulls = False):
d = frappe._dict()
for fieldname in self.meta.get_valid_columns():
d[fieldname] = self.get(fieldname)
@@ -234,6 +234,9 @@ class BaseDocument(object):
if convert_dates_to_str and isinstance(d[fieldname], (datetime.datetime, datetime.time, datetime.timedelta)):
d[fieldname] = str(d[fieldname])
+ if d[fieldname] == None and ignore_nulls:
+ del d[fieldname]
+
return d
def init_valid_columns(self):
@@ -306,7 +309,8 @@ class BaseDocument(object):
self.creation = self.modified = now()
self.created_by = self.modified_by = frappe.session.user
- d = self.get_valid_dict(convert_dates_to_str=True)
+ # if doctype is "DocType", don't insert null values as we don't know who is valid yet
+ d = self.get_valid_dict(convert_dates_to_str=True, ignore_nulls = self.doctype in ('DocType', 'DocField', 'DocPerm'))
columns = list(d)
try:
@@ -341,7 +345,7 @@ class BaseDocument(object):
self.db_insert()
return
- d = self.get_valid_dict(convert_dates_to_str=True)
+ d = self.get_valid_dict(convert_dates_to_str=True, ignore_nulls = self.doctype in ('DocType', 'DocField', 'DocPerm'))
# don't update name, as case might've been changed
name = d['name']
diff --git a/frappe/model/create_new.py b/frappe/model/create_new.py
index a4e50f704c..e882508c99 100644
--- a/frappe/model/create_new.py
+++ b/frappe/model/create_new.py
@@ -12,7 +12,7 @@ import frappe.defaults
from frappe.model import data_fieldtypes
from frappe.utils import nowdate, nowtime, now_datetime
from frappe.core.doctype.user_permission.user_permission import get_user_permissions
-from frappe.permissions import get_allowed_docs_for_doctype
+from frappe.permissions import filter_allowed_docs_for_doctype
def get_new_doc(doctype, parent_doc = None, parentfield = None, as_dict=False):
if doctype not in frappe.local.new_doc_templates:
@@ -56,12 +56,12 @@ def set_user_and_static_default_values(doc):
if df.fieldtype in data_fieldtypes:
# user permissions for link options
doctype_user_permissions = user_permissions.get(df.options, [])
- # Allowed records for the reference doctype (link field)
- allowed_records = get_allowed_docs_for_doctype(doctype_user_permissions, df.parent)
+ # Allowed records for the reference doctype (link field) along with default doc
+ allowed_records, default_doc = filter_allowed_docs_for_doctype(doctype_user_permissions, df.parent, with_default_doc=True)
- user_default_value = get_user_default_value(df, defaults, doctype_user_permissions, allowed_records)
+ user_default_value = get_user_default_value(df, defaults, doctype_user_permissions, allowed_records, default_doc)
if user_default_value != None:
- # do not set default if the field on which current field is dependent is not set
+ # do not set default if the field on which current field is dependent is not set
if is_dependent_field_set(df.depends_on, doc):
doc.set(df.fieldname, user_default_value)
else:
@@ -78,14 +78,14 @@ def is_dependent_field_set(fieldname, doc):
if fieldname not in value_dict: return True
return value_dict[fieldname]
-def get_user_default_value(df, defaults, doctype_user_permissions, allowed_records):
+def get_user_default_value(df, defaults, doctype_user_permissions, allowed_records, default_doc):
# don't set defaults for "User" link field using User Permissions!
if df.fieldtype == "Link" and df.options != "User":
# 1 - look in user permissions only for document_type==Setup
# We don't want to include permissions of transactions to be used for defaults.
if (frappe.get_meta(df.options).document_type=="Setup"
- and len(allowed_records)==1 and not df.ignore_user_permissions):
- return allowed_records[0]
+ and not df.ignore_user_permissions and default_doc):
+ return default_doc
# 2 - Look in user defaults
user_default = defaults.get(df.fieldname)
diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py
index 131374a1d6..8a557f3b3f 100644
--- a/frappe/model/delete_doc.py
+++ b/frappe/model/delete_doc.py
@@ -14,6 +14,8 @@ from frappe.model.naming import revert_series_if_last
from frappe.utils.global_search import delete_for_document
from six import string_types, integer_types
+doctypes_to_skip = ("Communication", "ToDo", "DocShare", "Email Unsubscribe", "Activity Log", "File", "Version", "Document Follow", "Comment" , "View Log")
+
def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False,
ignore_permissions=False, flags=None, ignore_on_trash=False, ignore_missing=True):
"""
@@ -64,6 +66,7 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa
frappe.db.sql("delete from `tabProperty Setter` where doc_type = %s", name)
frappe.db.sql("delete from `tabReport` where ref_doctype=%s", name)
frappe.db.sql("delete from `tabCustom DocPerm` where parent=%s", name)
+ frappe.db.sql("delete from `__global_search` where doctype=%s", name)
delete_from_table(doctype, name, ignore_doctypes, None)
@@ -195,7 +198,7 @@ def check_if_doc_is_linked(doc, method="Delete"):
for item in frappe.db.get_values(link_dt, {link_field:doc.name},
["name", "parent", "parenttype", "docstatus"], as_dict=True):
linked_doctype = item.parenttype if item.parent else link_dt
- if linked_doctype in ("Communication", "ToDo", "DocShare", "Email Unsubscribe", 'File', 'Version', "Activity Log", "Document Follow"):
+ if linked_doctype in doctypes_to_skip:
# don't check for communication and todo!
continue
@@ -220,7 +223,7 @@ def check_if_doc_is_linked(doc, method="Delete"):
def check_if_doc_is_dynamically_linked(doc, method="Delete"):
'''Raise `frappe.LinkExistsError` if the document is dynamically linked'''
for df in get_dynamic_link_map().get(doc.doctype, []):
- if df.parent in ("Communication", "ToDo", "DocShare", "Email Unsubscribe", "Activity Log", 'File', 'Version', 'View Log', "Document Follow"):
+ if df.parent in doctypes_to_skip:
# don't check for communication and todo!
continue
@@ -275,9 +278,8 @@ def delete_dynamic_links(doctype, name):
delete_references('Document Follow', doctype, name, 'ref_doctype', 'ref_docname')
# unlink communications
+ clear_timeline_references(doctype, name)
clear_references('Communication', doctype, name)
- clear_references('Communication', doctype, name, 'link_doctype', 'link_name')
- clear_references('Communication', doctype, name, 'timeline_doctype', 'timeline_name')
clear_references('Activity Log', doctype, name)
clear_references('Activity Log', doctype, name, 'timeline_doctype', 'timeline_name')
@@ -298,6 +300,9 @@ def clear_references(doctype, reference_doctype, reference_name,
{1}=%s and {2}=%s'''.format(doctype, reference_doctype_field, reference_name_field), # nosec
(reference_doctype, reference_name))
+def clear_timeline_references(link_doctype, link_name):
+ frappe.db.sql("""delete from `tabDynamic Link`
+ where `tabDynamic Link`.link_doctype='{0}' and `tabDynamic Link`.link_name='{1}'""".format(link_doctype, link_name)) # nosec
def insert_feed(doc):
from frappe.utils import get_fullname
diff --git a/frappe/model/document.py b/frappe/model/document.py
index c71e8e1a16..e8add2d619 100644
--- a/frappe/model/document.py
+++ b/frappe/model/document.py
@@ -117,6 +117,12 @@ class Document(BaseDocument):
# incorrect arguments. let's not proceed.
raise ValueError('Illegal arguments')
+ @staticmethod
+ def whitelist(f):
+ """Decorator: Whitelist method to be called remotely via REST API."""
+ f.whitelisted = True
+ return f
+
def reload(self):
"""Reload document from database"""
self.load_from_db()
@@ -224,6 +230,9 @@ class Document(BaseDocument):
self.set_docstatus()
self.flags.in_insert = False
+ # follow document on document creation
+
+
# run validate, on update etc.
# parent
@@ -253,6 +262,8 @@ class Document(BaseDocument):
if hasattr(self, "__islocal"):
delattr(self, "__islocal")
+ if not (frappe.flags.in_migrate or frappe.local.flags.in_install):
+ follow_document(self.doctype, self.name, frappe.session.user)
return self
def save(self, *args, **kwargs):
@@ -370,13 +381,7 @@ class Document(BaseDocument):
(self.name, self.doctype, fieldname))
def get_doc_before_save(self):
- if not getattr(self, '_doc_before_save', None):
- try:
- self._doc_before_save = frappe.get_doc(self.doctype, self.name)
- except frappe.DoesNotExistError:
- self._doc_before_save = None
- frappe.clear_last_message()
- return self._doc_before_save
+ return getattr(self, '_doc_before_save', None)
def set_new_name(self, force=False):
"""Calls `frappe.naming.se_new_name` for parent and child docs."""
@@ -834,11 +839,6 @@ class Document(BaseDocument):
elif alert.event=='Method' and method == alert.method:
_evaluate_alert(alert)
- @staticmethod
- def whitelist(f):
- f.whitelisted = True
- return f
-
@whitelist.__func__
def _submit(self):
"""Submit the document. Sets `docstatus` = 1, then saves."""
@@ -899,11 +899,12 @@ class Document(BaseDocument):
def load_doc_before_save(self):
'''Save load document from db before saving'''
self._doc_before_save = None
- if not (self.is_new()
- and (getattr(self.meta, 'track_changes', False)
- or self.meta.get_set_only_once_fields()
- or self.meta.get_workflow())):
- self.get_doc_before_save()
+ if not self.is_new():
+ try:
+ self._doc_before_save = frappe.get_doc(self.doctype, self.name)
+ except frappe.DoesNotExistError:
+ self._doc_before_save = None
+ frappe.clear_last_message()
def run_post_save_methods(self):
"""Run standard methods after `INSERT` or `UPDATE`. Standard Methods are:
@@ -1018,12 +1019,6 @@ class Document(BaseDocument):
if not frappe.flags.in_migrate:
follow_document(self.doctype, self.name, frappe.session.user)
- @staticmethod
- def whitelist(f):
- """Decorator: Whitelist method to be called remotely via REST API."""
- f.whitelisted = True
- return f
-
@staticmethod
def hook(f):
"""Decorator: Make method `hookable` (i.e. extensible by another app).
diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py
index a373554696..12c57f2780 100644
--- a/frappe/model/rename_doc.py
+++ b/frappe/model/rename_doc.py
@@ -161,7 +161,7 @@ def validate_rename(doctype, new, meta, merge, force, ignore_permissions):
if (not merge) and exists:
frappe.msgprint(_("Another {0} with name {1} exists, select another name").format(doctype, new), raise_exception=1)
- if not (ignore_permissions or frappe.has_permission(doctype, "write")):
+ if not (ignore_permissions or frappe.permissions.has_permission(doctype, "write", raise_exception=False)):
frappe.msgprint(_("You need write permission to rename"), raise_exception=1)
if not (force or ignore_permissions) and not meta.allow_rename:
diff --git a/frappe/modules/export_file.py b/frappe/modules/export_file.py
index 66a6a9f6b7..b904132530 100644
--- a/frappe/modules/export_file.py
+++ b/frappe/modules/export_file.py
@@ -23,6 +23,7 @@ def export_to_files(record_list=None, record_module=None, verbose=0, create_init
def write_document_file(doc, record_module=None, create_init=True):
newdoc = doc.as_dict(no_nulls=True)
+ doc.run_method("before_export", newdoc)
# strip out default fields from children
for df in doc.meta.get_table_fields():
@@ -38,7 +39,7 @@ def write_document_file(doc, record_module=None, create_init=True):
# write the data file
fname = scrub(doc.name)
- with open(os.path.join(folder, fname +".json"),'w+') as txtfile:
+ with open(os.path.join(folder, fname + ".json"), 'w+') as txtfile:
txtfile.write(frappe.as_json(newdoc))
def get_module_name(doc):
diff --git a/frappe/modules/import_file.py b/frappe/modules/import_file.py
index a1fa77d669..e250bfc42e 100644
--- a/frappe/modules/import_file.py
+++ b/frappe/modules/import_file.py
@@ -6,6 +6,7 @@ from __future__ import unicode_literals, print_function
import frappe, os, json
from frappe.modules import get_module_path, scrub_dt_dn
from frappe.utils import get_datetime_str
+from frappe.model.base_document import get_controller
ignore_values = {
"Report": ["disabled", "prepared_report"],
@@ -97,8 +98,15 @@ def import_doc(docdict, force=False, data_import=False, pre_process=None,
ignore_version=None, reset_permissions=False):
frappe.flags.in_import = True
docdict["__islocal"] = 1
+
+ controller = get_controller(docdict['doctype'])
+ if controller and hasattr(controller, 'prepare_for_import') and callable(getattr(controller, 'prepare_for_import')):
+ controller.prepare_for_import(docdict)
+
doc = frappe.get_doc(docdict)
+ doc.run_method("before_import")
+
doc.flags.ignore_version = ignore_version
if pre_process:
pre_process(doc)
diff --git a/frappe/patches.txt b/frappe/patches.txt
index d3b3ca02f1..911e793687 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -230,7 +230,6 @@ frappe.patches.v11_0.delete_all_prepared_reports
frappe.patches.v11_0.fix_order_by_in_reports_json
execute:frappe.delete_doc('Page', 'applications', ignore_missing=True)
frappe.patches.v11_0.set_missing_creation_and_modified_value_for_user_permissions
-frappe.patches.v11_0.remove_doctype_user_permissions_for_page_and_report
frappe.patches.v11_0.set_default_letter_head_source
frappe.patches.v12_0.set_primary_key_in_series
execute:frappe.delete_doc("Page", "modules", ignore_missing=True)
@@ -238,4 +237,8 @@ frappe.patches.v11_0.set_default_letter_head_source
frappe.patches.v12_0.setup_comments_from_communications
frappe.patches.v12_0.init_desk_settings #11-03-2019
frappe.patches.v12_0.replace_null_values_in_tables
-frappe.patches.v12_0.reset_home_settings
\ No newline at end of file
+frappe.patches.v12_0.reset_home_settings
+frappe.patches.v12_0.update_print_format_type
+frappe.patches.v11_0.remove_doctype_user_permissions_for_page_and_report #2019-05-01
+frappe.patches.v12_0.remove_feedback_rating
+frappe.patches.v12_0.move_timeline_links_to_dynamic_links
\ No newline at end of file
diff --git a/frappe/patches/v11_0/create_contact_for_user.py b/frappe/patches/v11_0/create_contact_for_user.py
index d5e9c87e8b..c91caf9189 100644
--- a/frappe/patches/v11_0/create_contact_for_user.py
+++ b/frappe/patches/v11_0/create_contact_for_user.py
@@ -6,6 +6,7 @@ import re
def execute():
""" Create Contact for each User if not present """
frappe.reload_doc('contacts', 'doctype', 'contact')
+ frappe.reload_doc('core', 'doctype', 'dynamic_link')
users = frappe.get_all('User', filters={"name": ('not in', 'Administrator, Guest')}, fields=["*"])
for user in users:
diff --git a/frappe/patches/v11_0/remove_doctype_user_permissions_for_page_and_report.py b/frappe/patches/v11_0/remove_doctype_user_permissions_for_page_and_report.py
index c1dc1b79be..e2c2ef5f0e 100644
--- a/frappe/patches/v11_0/remove_doctype_user_permissions_for_page_and_report.py
+++ b/frappe/patches/v11_0/remove_doctype_user_permissions_for_page_and_report.py
@@ -5,5 +5,4 @@ from __future__ import unicode_literals
import frappe
def execute():
- if frappe.db.table_exists('User Permission for Page and Report'):
- frappe.delete_doc("DocType", "User Permission for Page and Report")
\ No newline at end of file
+ frappe.delete_doc_if_exists("DocType", "User Permission for Page and Report")
\ No newline at end of file
diff --git a/frappe/patches/v11_0/set_default_letter_head_source.py b/frappe/patches/v11_0/set_default_letter_head_source.py
index 069f4e3d2e..a43ea397e4 100644
--- a/frappe/patches/v11_0/set_default_letter_head_source.py
+++ b/frappe/patches/v11_0/set_default_letter_head_source.py
@@ -6,4 +6,4 @@ def execute():
frappe.reload_doctype('Letter Head')
# source of all existing letter heads must be HTML
- frappe.db.sql('update `tabLetter Head` set source = "HTML"')
\ No newline at end of file
+ frappe.db.sql("update `tabLetter Head` set source = 'HTML'")
diff --git a/frappe/patches/v12_0/init_desk_settings.py b/frappe/patches/v12_0/init_desk_settings.py
index 782ced8a26..31c6cf9207 100644
--- a/frappe/patches/v12_0/init_desk_settings.py
+++ b/frappe/patches/v12_0/init_desk_settings.py
@@ -8,4 +8,4 @@ from frappe.desk.moduleview import get_onboard_items
def execute():
"""Reset the initial customizations for desk, with modules, indices and links."""
frappe.reload_doc("core", "doctype", "user")
- frappe.db.sql("""update tabUser set home_settings = %s""", (''), debug=True)
+ frappe.db.sql("""update `tabUser` set home_settings = %s""", (''), debug=True)
diff --git a/frappe/patches/v12_0/move_timeline_links_to_dynamic_links.py b/frappe/patches/v12_0/move_timeline_links_to_dynamic_links.py
new file mode 100644
index 0000000000..873988c7f3
--- /dev/null
+++ b/frappe/patches/v12_0/move_timeline_links_to_dynamic_links.py
@@ -0,0 +1,46 @@
+from __future__ import unicode_literals
+
+import frappe
+
+def execute():
+ frappe.reload_doc('core', 'doctype', 'communication')
+
+ communications = frappe.db.sql("""
+ SELECT
+ `tabCommunication`.name, `tabCommunication`.creation, `tabCommunication`.modified,
+ `tabCommunication`.modified_by,`tabCommunication`.timeline_doctype, `tabCommunication`.timeline_name,
+ `tabCommunication`.link_doctype, `tabCommunication`.link_name
+ FROM `tabCommunication`
+ WHERE `tabCommunication`.communication_medium='Email'
+ """, as_dict=True)
+
+ for count, communication in enumerate(communications):
+ counter = 1
+ if communication.timeline_doctype and communication.timeline_name:
+ values = [
+ counter, frappe.generate_hash(length=10), 'timeline_links', 'Communication', communication.name,
+ communication.timeline_doctype, communication.timeline_name, communication.creation, communication.modified,
+ communication.modified_by
+ ]
+ execute_query(values)
+ counter += 1
+
+ if communication.link_doctype and communication.link_name:
+ values = [
+ counter, frappe.generate_hash(length=10), 'timeline_links', 'Communication', communication.name,
+ communication.link_doctype, communication.link_name, communication.creation, communication.modified,
+ communication.modified_by
+ ]
+ execute_query(values)
+
+def execute_query(values):
+ try:
+ frappe.db.sql("""
+ INSERT INTO `tabDynamic Link`
+ (`idx`, `name`, `parentfield`, `parenttype`, `parent`, `link_doctype`, `link_name`, `creation`,
+ `modified`, `modified_by`)
+ VALUES ({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9})
+ """.format(values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8], values[9]))
+ except Exception as e:
+ values[1] = frappe.generate_hash(length=10)
+ execute_query(values)
diff --git a/frappe/patches/v12_0/remove_feedback_rating.py b/frappe/patches/v12_0/remove_feedback_rating.py
new file mode 100644
index 0000000000..5184bb7b79
--- /dev/null
+++ b/frappe/patches/v12_0/remove_feedback_rating.py
@@ -0,0 +1,9 @@
+import frappe
+
+def execute():
+ '''
+ Deprecate Feedback Trigger and Rating. This feature was not customizable.
+ Now can be achieved via custom Web Forms
+ '''
+ frappe.delete_doc('DocType', 'Feedback Trigger')
+ frappe.delete_doc('DocType', 'Feedback Rating')
diff --git a/frappe/patches/v12_0/setup_comments_from_communications.py b/frappe/patches/v12_0/setup_comments_from_communications.py
index 1a7a5aef84..b52304bc05 100644
--- a/frappe/patches/v12_0/setup_comments_from_communications.py
+++ b/frappe/patches/v12_0/setup_comments_from_communications.py
@@ -25,4 +25,4 @@ def execute():
new_comment.db_insert()
# clean up
- frappe.db.sql('delete from tabCommunication where communication_type = "Comment"')
\ No newline at end of file
+ frappe.db.sql("delete from `tabCommunication` where communication_type = 'Comment'")
diff --git a/frappe/patches/v12_0/update_print_format_type.py b/frappe/patches/v12_0/update_print_format_type.py
new file mode 100644
index 0000000000..577dc68d94
--- /dev/null
+++ b/frappe/patches/v12_0/update_print_format_type.py
@@ -0,0 +1,13 @@
+import frappe
+
+def execute():
+ frappe.db.sql('''
+ UPDATE `tabPrint Format`
+ SET `print_format_type` = 'Jinja'
+ WHERE `print_format_type` in ('Server', 'Client')
+ ''')
+ frappe.db.sql('''
+ UPDATE `tabPrint Format`
+ SET `print_format_type` = 'JS'
+ WHERE `print_format_type` = 'Js'
+ ''')
diff --git a/frappe/patches/v5_0/convert_to_barracuda_and_utf8mb4.py b/frappe/patches/v5_0/convert_to_barracuda_and_utf8mb4.py
index 0e4a334a76..0ea2ee2387 100644
--- a/frappe/patches/v5_0/convert_to_barracuda_and_utf8mb4.py
+++ b/frappe/patches/v5_0/convert_to_barracuda_and_utf8mb4.py
@@ -1,10 +1,10 @@
from __future__ import unicode_literals
import frappe
-from frappe.database.mariadb.setup_db import check_if_ready_for_barracuda
+from frappe.database.mariadb.setup_db import check_database_settings
from frappe.model.meta import trim_tables
def execute():
- check_if_ready_for_barracuda()
+ check_database_settings()
for table in frappe.db.get_tables():
frappe.db.sql_ddl("""alter table `{0}` ENGINE=InnoDB ROW_FORMAT=COMPRESSED""".format(table))
diff --git a/frappe/patches/v7_2/update_communications.py b/frappe/patches/v7_2/update_communications.py
index 98c729ae41..f3d859b95a 100644
--- a/frappe/patches/v7_2/update_communications.py
+++ b/frappe/patches/v7_2/update_communications.py
@@ -7,18 +7,4 @@ def execute():
remove Guest None from sender full name
setup feedback request trigger's is_manual field
"""
- frappe.reload_doc('core', 'doctype', 'dynamic_link')
- frappe.reload_doc('email', 'doctype', 'contact')
-
- frappe.reload_doc("core", "doctype", "feedback_request")
- frappe.reload_doc("core", "doctype", "communication")
-
- if frappe.db.has_column('Communication', 'feedback'):
- frappe.db.sql("""update tabCommunication set content=ifnull(feedback, "feedback details not provided")
- where communication_type="Feedback" and content is NULL""")
-
- frappe.db.sql(""" update tabCommunication set sender_full_name="" where communication_type="Feedback"
- and sender_full_name='Guest None' """)
-
- frappe.db.sql(""" update `tabFeedback Request` set is_manual=1, feedback_trigger="Manual"
- where ifnull(feedback_trigger, '')='' """)
\ No newline at end of file
+ return
diff --git a/frappe/patches/v7_2/update_feedback_request.py b/frappe/patches/v7_2/update_feedback_request.py
index 68814e7a58..11e9eb8e92 100644
--- a/frappe/patches/v7_2/update_feedback_request.py
+++ b/frappe/patches/v7_2/update_feedback_request.py
@@ -7,29 +7,4 @@ def execute():
update the feedback request and save the rating and communication
reference in Feedback Request document
"""
-
- frappe.reload_doc("core", "doctype", "feedback_request")
- feedback_requests = frappe.get_all("Feedback Request")
- for request in feedback_requests:
- communication, rating = frappe.db.get_value("Communication", { "feedback_request": request.get("name") },
- ["name", "rating"]) or [None, 0]
-
- if communication:
- frappe.db.sql("""update `tabFeedback Request` set reference_communication='{communication}',
- rating={rating} where name='{feedback_request}'""".format(
- communication=communication,
- rating=rating or 0,
- feedback_request=request.get("name")
- ))
-
- if "Feedback" not in request.get("name"):
- # rename the feedback request doc
- reference_name, creation = frappe.db.get_value("Feedback Request", request.get("name"), ["name", "creation"])
- oldname = request.get("name")
- newname = "Feedback for {doctype} {docname} on {datetime}".format(
- doctype="Feedback Request",
- docname=reference_name,
- datetime=creation
- )
- frappe.rename_doc("Feedback Request", oldname, newname, ignore_permissions=True)
- if communication: frappe.db.set_value("Communication", communication, "feedback_request", newname)
\ No newline at end of file
+ return
diff --git a/frappe/permissions.py b/frappe/permissions.py
index 6c3c5b7739..e5aa31d139 100644
--- a/frappe/permissions.py
+++ b/frappe/permissions.py
@@ -25,16 +25,18 @@ def print_has_permission_check_logs(func):
frappe.flags['has_permission_check_logs'] = []
result = func(*args, **kwargs)
self_perm_check = True if not kwargs.get('user') else kwargs.get('user') == frappe.session.user
+ raise_exception = False if kwargs.get('raise_exception') == False else True
+
# print only if access denied
# and if user is checking his own permission
- if not result and self_perm_check:
+ if not result and self_perm_check and raise_exception:
msgprint((' ').join(frappe.flags.get('has_permission_check_logs')))
frappe.flags.pop('has_permission_check_logs', None)
return result
return inner
@print_has_permission_check_logs
-def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None):
+def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None, raise_exception=True):
"""Returns True if user has permission `ptype` for given `doctype`.
If `doc` is passed, it also checks user, share and owner permissions.
@@ -395,7 +397,7 @@ def set_user_permission_if_allowed(doctype, name, user, with_message=False):
if get_role_permissions(frappe.get_meta(doctype), user).set_user_permissions!=1:
add_user_permission(doctype, name, user)
-def add_user_permission(doctype, name, user, ignore_permissions=False, applicable_for=None):
+def add_user_permission(doctype, name, user, ignore_permissions=False, applicable_for=None, is_default=0):
'''Add user permission'''
from frappe.core.doctype.user_permission.user_permission import user_permission_exists
@@ -408,6 +410,7 @@ def add_user_permission(doctype, name, user, ignore_permissions=False, applicabl
user=user,
allow=doctype,
for_value=name,
+ is_default=is_default,
applicable_for=applicable_for,
)).insert(ignore_permissions=ignore_permissions)
@@ -523,9 +526,22 @@ def allow_everything():
return perm
def get_allowed_docs_for_doctype(user_permissions, doctype):
- '''Returns all the docs from the passed user_permission
- that are allowed under provide doctype'''
- return [d.get('doc') for d in user_permissions if not d.get('applicable_for') or d.get('applicable_for') == doctype]
+ ''' Returns all the docs from the passed user_permissions that are
+ allowed under provided doctype '''
+ return filter_allowed_docs_for_doctype(user_permissions, doctype, with_default_doc=False)
+
+def filter_allowed_docs_for_doctype(user_permissions, doctype, with_default_doc=True):
+ ''' Returns all the docs from the passed user_permissions that are
+ allowed under provided doctype along with default doc value if with_default_doc is set '''
+ allowed_doc = []
+ default_doc = None
+ for doc in user_permissions:
+ if not doc.get('applicable_for') or doc.get('applicable_for') == doctype:
+ allowed_doc.append(doc.get('doc'))
+ if doc.get('is_default') or len(user_permissions) == 1 and with_default_doc:
+ default_doc = doc.get('doc')
+
+ return (allowed_doc, default_doc) if with_default_doc else allowed_doc
def push_perm_check_log(log):
if frappe.flags.get('has_permission_check_logs') == None: return
diff --git a/frappe/printing/doctype/print_format/print_format.json b/frappe/printing/doctype/print_format/print_format.json
index f8c8f97105..d61bbda614 100644
--- a/frappe/printing/doctype/print_format/print_format.json
+++ b/frappe/printing/doctype/print_format/print_format.json
@@ -1,767 +1,905 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 1,
- "autoname": "Prompt",
- "beta": 0,
- "creation": "2013-01-23 19:54:43",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 1,
+ "autoname": "Prompt",
+ "beta": 0,
+ "creation": "2013-01-23 19:54:43",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "editable_grid": 0,
+ "engine": "InnoDB",
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "doc_type",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "DocType",
- "length": 0,
- "no_copy": 0,
- "options": "DocType",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "module",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Module",
- "length": 0,
- "no_copy": 0,
- "options": "Module Def",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "disabled",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Disabled",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "No",
- "fieldname": "standard",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Standard",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "standard",
- "oldfieldtype": "Select",
- "options": "No\nYes",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "custom_format",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Custom Format",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "custom_format",
- "fieldname": "section_break_6",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Server",
- "depends_on": "custom_format",
- "description": "",
- "fieldname": "print_format_type",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print Format Type",
- "length": 0,
- "no_copy": 0,
- "options": "Server\nClient\nJs",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "custom_format",
- "fieldname": "html",
- "fieldtype": "Code",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "HTML",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "html",
- "oldfieldtype": "Text Editor",
- "options": "HTML",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.custom_format",
- "fieldname": "section_break_9",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Style Settings",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "align_labels_right",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Align Labels to the Right",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "show_section_headings",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Show Section Headings",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "line_breaks",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Show Line Breaks after Sections",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_11",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "",
+ "fetch_if_empty": 0,
+ "fieldname": "doc_type",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 1,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "DocType",
+ "length": 0,
+ "no_copy": 0,
+ "options": "DocType",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "default_print_language",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Print Language",
- "length": 0,
- "no_copy": 0,
- "options": "Language",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "module",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Module",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Module Def",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Default",
- "depends_on": "eval:!doc.custom_format",
- "fieldname": "font",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Font",
- "length": 0,
- "no_copy": 0,
- "options": "Default\nArial\nHelvetica\nVerdana\nMonospace",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Disabled",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "css_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "css",
- "fieldtype": "Code",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Custom CSS",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "No",
+ "fetch_if_empty": 0,
+ "fieldname": "standard",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 1,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Standard",
+ "length": 0,
+ "no_copy": 1,
+ "oldfieldname": "standard",
+ "oldfieldtype": "Select",
+ "options": "No\nYes",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 1,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "custom_html_help",
- "fieldtype": "HTML",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Custom HTML Help",
- "length": 0,
- "no_copy": 0,
- "options": "Custom CSS Help \n\nNotes:
\n\n\nAll field groups (label + value) are set attributes data-fieldtype and data-fieldname \nAll values are given class value \nAll Section Breaks are given class section-break \nAll Column Breaks are given class column-break \n \n\nExamples \n\n1. Left align integers
\n\n[data-fieldtype=\"Int\"] .value { text-left: left; } \n\n1. Add border to sections except the last section
\n\n.section-break { padding: 30px 0px; border-bottom: 1px solid #eee; }\n.section-break:last-child { padding-bottom: 0px; border-bottom: 0px; } \n",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "custom_format",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Custom Format",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "custom_format",
- "fieldname": "section_break_13",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "custom_format",
+ "fetch_if_empty": 0,
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "custom_format",
- "fieldname": "print_format_help",
- "fieldtype": "HTML",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print Format Help",
- "length": 0,
- "no_copy": 0,
- "options": "Print Format Help \n \nIntroduction \nPrint itemsFormats are rendered on the server side using the Jinja Templating Language. All forms have access to the doc object which contains information about the document that is being formatted. You can also access common utilities via the frappe module.
\nFor styling, the Boostrap CSS framework is provided and you can enjoy the full range of classes.
\n \nReferences \n\n\tJinja Tempalting Language: Reference \n\tBootstrap CSS Framework \n \n \nExample \n<h3>{{ doc.select_print_heading or \"Invoice\" }}</h3>\n<div class=\"row\">\n\t<div class=\"col-md-3 text-right\">Customer Name</div>\n\t<div class=\"col-md-9\">{{ doc.customer_name }}</div>\n</div>\n<div class=\"row\">\n\t<div class=\"col-md-3 text-right\">Date</div>\n\t<div class=\"col-md-9\">{{ doc.get_formatted(\"invoice_date\") }}</div>\n</div>\n<table class=\"table table-bordered\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<th>Sr</th>\n\t\t\t<th>Item Name</th>\n\t\t\t<th>Description</th>\n\t\t\t<th class=\"text-right\">Qty</th>\n\t\t\t<th class=\"text-right\">Rate</th>\n\t\t\t<th class=\"text-right\">Amount</th>\n\t\t</tr>\n\t\t{%- for row in doc.items -%}\n\t\t<tr>\n\t\t\t<td style=\"width: 3%;\">{{ row.idx }}</td>\n\t\t\t<td style=\"width: 20%;\">\n\t\t\t\t{{ row.item_name }}\n\t\t\t\t{% if row.item_code != row.item_name -%}\n\t\t\t\t<br>Item Code: {{ row.item_code}}\n\t\t\t\t{%- endif %}\n\t\t\t</td>\n\t\t\t<td style=\"width: 37%;\">\n\t\t\t\t<div style=\"border: 0px;\">{{ row.description }}</div></td>\n\t\t\t<td style=\"width: 10%; text-align: right;\">{{ row.qty }} {{ row.uom or row.stock_uom }}</td>\n\t\t\t<td style=\"width: 15%; text-align: right;\">{{\n\t\t\t\trow.get_formatted(\"rate\", doc) }}</td>\n\t\t\t<td style=\"width: 15%; text-align: right;\">{{\n\t\t\t\trow.get_formatted(\"amount\", doc) }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table> \n \nCommon Functions \n\n\t\n\t\t\n\t\t\tdoc.get_formatted(\"[fieldname]\", [parent_doc]) \n\t\t\tGet document value formatted as Date, Currency etc. Pass parent doc for curreny type fields. \n\t\t \n\t\t\n\t\t\tfrappe.db.get_value(\"[doctype]\", \"[name]\", \"fieldname\") \n\t\t\tGet value from another document. \n\t\t \n\t \n
\n",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Jinja",
+ "depends_on": "custom_format",
+ "description": "",
+ "fetch_if_empty": 0,
+ "fieldname": "print_format_type",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Print Format Type",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Jinja\nJS",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "format_data",
- "fieldtype": "Code",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Format Data",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "",
+ "fetch_if_empty": 0,
+ "fieldname": "raw_printing",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Raw Printing",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "print_format_builder",
- "fieldtype": "Check",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print Format Builder",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "eval:!doc.raw_printing",
+ "fetch_if_empty": 0,
+ "fieldname": "html",
+ "fieldtype": "Code",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "HTML",
+ "length": 0,
+ "no_copy": 0,
+ "oldfieldname": "html",
+ "oldfieldtype": "Text Editor",
+ "options": "HTML",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "raw_printing",
+ "description": "Any string-based printer languages can be used. Writing raw commands requires knowledge of the printer's native language provided by the printer manufacturer. Please refer to the developer manual provided by the printer manufacturer on how to write their native commands. These commands are rendered on the server side using the Jinja Templating Language.",
+ "fetch_if_empty": 0,
+ "fieldname": "raw_commands",
+ "fieldtype": "Code",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Raw Commands",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "eval:!doc.custom_format",
+ "fetch_if_empty": 0,
+ "fieldname": "section_break_9",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Style Settings",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "fetch_if_empty": 0,
+ "fieldname": "align_labels_right",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Align Labels to the Right",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "fetch_if_empty": 0,
+ "fieldname": "show_section_headings",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Show Section Headings",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "fetch_if_empty": 0,
+ "fieldname": "line_breaks",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Show Line Breaks after Sections",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "default_print_language",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Default Print Language",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Language",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Default",
+ "depends_on": "eval:!doc.custom_format",
+ "fetch_if_empty": 0,
+ "fieldname": "font",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Font",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Default\nArial\nHelvetica\nVerdana\nMonospace",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "eval:!doc.raw_printing",
+ "fetch_if_empty": 0,
+ "fieldname": "css_section",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "css",
+ "fieldtype": "Code",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Custom CSS",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "custom_html_help",
+ "fieldtype": "HTML",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Custom HTML Help",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Custom CSS Help \n\nNotes:
\n\n\nAll field groups (label + value) are set attributes data-fieldtype and data-fieldname \nAll values are given class value \nAll Section Breaks are given class section-break \nAll Column Breaks are given class column-break \n \n\nExamples \n\n1. Left align integers
\n\n[data-fieldtype=\"Int\"] .value { text-left: left; } \n\n1. Add border to sections except the last section
\n\n.section-break { padding: 30px 0px; border-bottom: 1px solid #eee; }\n.section-break:last-child { padding-bottom: 0px; border-bottom: 0px; } \n",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "custom_format",
+ "fetch_if_empty": 0,
+ "fieldname": "section_break_13",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "custom_format",
+ "fetch_if_empty": 0,
+ "fieldname": "print_format_help",
+ "fieldtype": "HTML",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Print Format Help",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Print Format Help \n \nIntroduction \nPrint itemsFormats are rendered on the server side using the Jinja Templating Language. All forms have access to the doc object which contains information about the document that is being formatted. You can also access common utilities via the frappe module.
\nFor styling, the Boostrap CSS framework is provided and you can enjoy the full range of classes.
\n \nReferences \n\n\tJinja Tempalting Language: Reference \n\tBootstrap CSS Framework \n \n \nExample \n<h3>{{ doc.select_print_heading or \"Invoice\" }}</h3>\n<div class=\"row\">\n\t<div class=\"col-md-3 text-right\">Customer Name</div>\n\t<div class=\"col-md-9\">{{ doc.customer_name }}</div>\n</div>\n<div class=\"row\">\n\t<div class=\"col-md-3 text-right\">Date</div>\n\t<div class=\"col-md-9\">{{ doc.get_formatted(\"invoice_date\") }}</div>\n</div>\n<table class=\"table table-bordered\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<th>Sr</th>\n\t\t\t<th>Item Name</th>\n\t\t\t<th>Description</th>\n\t\t\t<th class=\"text-right\">Qty</th>\n\t\t\t<th class=\"text-right\">Rate</th>\n\t\t\t<th class=\"text-right\">Amount</th>\n\t\t</tr>\n\t\t{%- for row in doc.items -%}\n\t\t<tr>\n\t\t\t<td style=\"width: 3%;\">{{ row.idx }}</td>\n\t\t\t<td style=\"width: 20%;\">\n\t\t\t\t{{ row.item_name }}\n\t\t\t\t{% if row.item_code != row.item_name -%}\n\t\t\t\t<br>Item Code: {{ row.item_code}}\n\t\t\t\t{%- endif %}\n\t\t\t</td>\n\t\t\t<td style=\"width: 37%;\">\n\t\t\t\t<div style=\"border: 0px;\">{{ row.description }}</div></td>\n\t\t\t<td style=\"width: 10%; text-align: right;\">{{ row.qty }} {{ row.uom or row.stock_uom }}</td>\n\t\t\t<td style=\"width: 15%; text-align: right;\">{{\n\t\t\t\trow.get_formatted(\"rate\", doc) }}</td>\n\t\t\t<td style=\"width: 15%; text-align: right;\">{{\n\t\t\t\trow.get_formatted(\"amount\", doc) }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table> \n \nCommon Functions \n\n\t\n\t\t\n\t\t\tdoc.get_formatted(\"[fieldname]\", [parent_doc]) \n\t\t\tGet document value formatted as Date, Currency etc. Pass parent doc for curreny type fields. \n\t\t \n\t\t\n\t\t\tfrappe.db.get_value(\"[doctype]\", \"[name]\", \"fieldname\") \n\t\t\tGet value from another document. \n\t\t \n\t \n
\n",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "format_data",
+ "fieldtype": "Code",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Format Data",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "print_format_builder",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Print Format Builder",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-print",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-09-05 14:02:05.658719",
- "modified_by": "Administrator",
- "module": "Printing",
- "name": "Print Format",
- "owner": "Administrator",
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "icon": "fa fa-print",
+ "idx": 1,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "menu_index": 0,
+ "modified": "2019-04-20 12:45:25.869180",
+ "modified_by": "Administrator",
+ "module": "Printing",
+ "name": "Print Format",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/frappe/printing/doctype/print_format/print_format.py b/frappe/printing/doctype/print_format/print_format.py
index 8f25ab7cb8..8b48fb5705 100644
--- a/frappe/printing/doctype/print_format/print_format.py
+++ b/frappe/printing/doctype/print_format/print_format.py
@@ -27,7 +27,7 @@ class PrintFormat(Document):
if not self.module:
self.module = frappe.db.get_value('DocType', self.doc_type, 'module')
- if self.html and self.print_format_type != 'Js':
+ if self.html and self.print_format_type != 'JS':
validate_template(self.html)
def extract_images(self):
diff --git a/frappe/printing/doctype/print_settings/print_settings.json b/frappe/printing/doctype/print_settings/print_settings.json
index 4f7039c7f8..397d9dda5d 100644
--- a/frappe/printing/doctype/print_settings/print_settings.json
+++ b/frappe/printing/doctype/print_settings/print_settings.json
@@ -1,843 +1,932 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2014-07-17 06:54:20.782907",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "System",
- "editable_grid": 0,
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2014-07-17 06:54:20.782907",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "System",
+ "editable_grid": 0,
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "pdf_settings",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "PDF Settings",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "pdf_settings",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "PDF Settings",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "description": "Send Email Print Attachments as PDF (Recommended)",
- "fieldname": "send_print_as_pdf",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Send Print as PDF",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "1",
+ "description": "Send Email Print Attachments as PDF (Recommended)",
+ "fetch_if_empty": 0,
+ "fieldname": "send_print_as_pdf",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Send Print as PDF",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fieldname": "repeat_header_footer",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Repeat Header and Footer in PDF",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "1",
+ "fetch_if_empty": 0,
+ "fieldname": "repeat_header_footer",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Repeat Header and Footer in PDF",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "A4",
- "fieldname": "pdf_page_size",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "PDF Page Size",
- "length": 0,
- "no_copy": 0,
- "options": "A4\nLetter",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "A4",
+ "fetch_if_empty": 0,
+ "fieldname": "pdf_page_size",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "PDF Page Size",
+ "length": 0,
+ "no_copy": 0,
+ "options": "A4\nLetter",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "view_link_in_email",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Page Settings",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "view_link_in_email",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Page Settings",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "description": "",
- "fieldname": "with_letterhead",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print with letterhead",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "1",
+ "description": "",
+ "fetch_if_empty": 0,
+ "fieldname": "with_letterhead",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Print with letterhead",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "description": "",
- "fieldname": "allow_print_for_draft",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Print for Draft",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "1",
+ "description": "",
+ "fetch_if_empty": 0,
+ "fieldname": "allow_print_for_draft",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Allow Print for Draft",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "description": "",
- "fieldname": "attach_view_link",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Send document web view link in email",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "1",
+ "description": "",
+ "fetch_if_empty": 0,
+ "fieldname": "attach_view_link",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Send document web view link in email",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_10",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_10",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fieldname": "add_draft_heading",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Always add \"Draft\" Heading for printing draft documents",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "1",
+ "fetch_if_empty": 0,
+ "fieldname": "add_draft_heading",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Always add \"Draft\" Heading for printing draft documents",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "allow_page_break_inside_tables",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow page break inside tables",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "allow_page_break_inside_tables",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Allow page break inside tables",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "allow_print_for_cancelled",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Print for Cancelled",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "",
+ "fetch_if_empty": 0,
+ "fieldname": "allow_print_for_cancelled",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Allow Print for Cancelled",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "server_printer",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print Server",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "",
+ "fetch_if_empty": 0,
+ "fieldname": "server_printer",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Print Server",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "enable_print_server",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Enable Print Server",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "enable_print_server",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Enable Print Server",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "localhost",
- "depends_on": "enable_print_server",
- "fieldname": "server_ip",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Server IP",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "localhost",
+ "depends_on": "enable_print_server",
+ "fetch_if_empty": 0,
+ "fieldname": "server_ip",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Server IP",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "enable_print_server",
- "fieldname": "printer_name",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Printer Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "enable_print_server",
+ "fetch_if_empty": 0,
+ "fieldname": "printer_name",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Printer Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "631",
- "depends_on": "enable_print_server",
- "fieldname": "port",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Port",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "631",
+ "depends_on": "enable_print_server",
+ "fetch_if_empty": 0,
+ "fieldname": "port",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Port",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "print_style_section",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print Style",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "raw_printing_section",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Raw Printing",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Modern",
- "fieldname": "print_style",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Print Style",
- "length": 0,
- "no_copy": 0,
- "options": "Print Style",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "enable_raw_printing",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Enable Raw Printing",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "print_style_preview",
- "fieldtype": "HTML",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Print Style Preview",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "print_style_section",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Print Style",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_8",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Fonts",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Modern",
+ "fetch_if_empty": 0,
+ "fieldname": "print_style",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Print Style",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Print Style",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Default",
- "fieldname": "font",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Font",
- "length": 0,
- "no_copy": 0,
- "options": "Default\nArial\nHelvetica\nVerdana\nMonospace",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "print_style_preview",
+ "fieldtype": "HTML",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Print Style Preview",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "In points. Default is 9.",
- "fieldname": "font_size",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Font Size",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Fonts",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Default",
+ "fetch_if_empty": 0,
+ "fieldname": "font",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Font",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Default\nArial\nHelvetica\nVerdana\nMonospace",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "In points. Default is 9.",
+ "fetch_if_empty": 0,
+ "fieldname": "font_size",
+ "fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Font Size",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-cog",
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-09-20 12:10:14.440598",
- "modified_by": "Administrator",
- "module": "Printing",
- "name": "Print Settings",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "icon": "fa fa-cog",
+ "idx": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 1,
+ "istable": 0,
+ "max_attachments": 0,
+ "menu_index": 0,
+ "modified": "2019-04-10 14:12:31.081187",
+ "modified_by": "Administrator",
+ "module": "Printing",
+ "name": "Print Settings",
+ "name_case": "",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 0,
+ "email": 0,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 0,
+ "read": 1,
+ "report": 0,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
"write": 1
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
"track_views": 0
}
\ No newline at end of file
diff --git a/frappe/printing/page/print_format_builder/print_format_builder.js b/frappe/printing/page/print_format_builder/print_format_builder.js
index 8e21ee4f50..aa733cbe31 100644
--- a/frappe/printing/page/print_format_builder/print_format_builder.js
+++ b/frappe/printing/page/print_format_builder/print_format_builder.js
@@ -12,10 +12,9 @@ frappe.pages['print-format-builder'].on_page_show = function(wrapper) {
});
} else if(frappe.route_options) {
if(frappe.route_options.make_new) {
- var doctype = frappe.route_options.doctype;
- var name = frappe.route_options.name;
+ let { doctype, name, based_on } = frappe.route_options;
frappe.route_options = null;
- frappe.print_format_builder.setup_new_print_format(doctype, name);
+ frappe.print_format_builder.setup_new_print_format(doctype, name, based_on);
} else {
frappe.print_format_builder.print_format = frappe.route_options.doc;
frappe.route_options = null;
@@ -130,23 +129,16 @@ frappe.PrintFormatBuilder = Class.extend({
});
},
- setup_new_print_format: function(doctype, name) {
- var me = this;
- frappe.call({
- method: "frappe.client.insert",
- args: {
- doc: {
- doctype: "Print Format",
- name: name,
- standard: "No",
- doc_type: doctype,
- print_format_builder: 1
- }
- },
- callback: function(r) {
- me.print_format = r.message;
- me.refresh();
- }
+ setup_new_print_format: function(doctype, name, based_on) {
+ frappe.call('frappe.printing.page.print_format_builder.print_format_builder.create_custom_format', {
+ doctype,
+ name,
+ based_on
+ }).then((r) => {
+ frappe.model.with_doc('Print Format', r.message.name)
+ .then(() => $(document).trigger({ type: 'new-print-format', print_format: r.message.name }));
+ this.print_format = r.message;
+ this.refresh();
});
},
setup_print_format: function() {
@@ -785,6 +777,8 @@ frappe.PrintFormatBuilder = Class.extend({
fieldname: "format_data",
value: JSON.stringify(data),
},
+ freeze: true,
+ btn: this.page.btn_primary,
callback: function(r) {
me.print_format = r.message;
frappe.show_alert({message: __("Saved"), indicator: 'green'});
diff --git a/frappe/printing/page/print_format_builder/print_format_builder.py b/frappe/printing/page/print_format_builder/print_format_builder.py
new file mode 100644
index 0000000000..17baa9314e
--- /dev/null
+++ b/frappe/printing/page/print_format_builder/print_format_builder.py
@@ -0,0 +1,12 @@
+import frappe
+
+@frappe.whitelist()
+def create_custom_format(doctype, name, based_on):
+ doc = frappe.new_doc('Print Format')
+ doc.doc_type = doctype
+ doc.name = name
+ doc.print_format_builder = 1
+ doc.format_data = frappe.db.get_value('Print Format', based_on, 'format_data') \
+ if based_on != 'Standard' else None
+ doc.insert()
+ return doc
diff --git a/frappe/public/build.json b/frappe/public/build.json
index 620b360f47..cd8f04b2c9 100755
--- a/frappe/public/build.json
+++ b/frappe/public/build.json
@@ -123,6 +123,7 @@
"public/less/page.less",
"public/less/tree.less",
"public/less/desktop.less",
+ "public/less/link_preview.less",
"public/less/form.less",
"public/less/mobile.less",
"public/less/kanban.less",
@@ -167,6 +168,7 @@
"public/js/frappe/ui/keyboard.js",
"public/js/frappe/ui/colors.js",
"public/js/frappe/ui/sidebar.js",
+ "public/js/frappe/ui/link_preview.js",
"public/js/frappe/request.js",
"public/js/frappe/socketio_client.js",
@@ -252,7 +254,6 @@
"public/js/frappe/ui/comment.js",
"public/js/frappe/misc/rating_icons.html",
- "public/js/frappe/feedback.js",
"public/js/frappe/chat.js",
"public/js/frappe/social/social_factory.js",
"public/js/frappe/misc/energy_point_utils.js"
@@ -357,9 +358,7 @@
"public/js/lib/clusterize.min.js",
"public/js/frappe/views/reports/report_factory.js",
"public/js/frappe/views/reports/report_view.js",
- "public/js/frappe/views/reports/reportview_footer.html",
"public/js/frappe/views/reports/query_report.js",
- "public/js/frappe/views/reports/grid_report.js",
"public/js/frappe/views/reports/print_grid.html",
"public/js/frappe/views/reports/print_tree.html",
"public/js/frappe/ui/group_by/group_by.html",
diff --git a/frappe/public/js/frappe/chat.js b/frappe/public/js/frappe/chat.js
index 3dc6fe6505..533ca90856 100644
--- a/frappe/public/js/frappe/chat.js
+++ b/frappe/public/js/frappe/chat.js
@@ -2132,10 +2132,11 @@ class extends Component {
icon: "file",
label: "File",
onclick: ( ) => {
- const dialog = frappe.upload.make({
- args: { doctype: "Chat Room", docname: props.name },
- callback: (a, b, args) => {
- const { file_url, filename } = args
+ new frappe.ui.FileUploader({
+ doctype: "Chat Room",
+ docname: props.name,
+ on_success(file_doc) {
+ const { file_url, filename } = file_doc
frappe.chat.message.send(props.name, { path: file_url, name: filename }, "File")
}
})
diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js
index db85dce81f..27b483b7aa 100644
--- a/frappe/public/js/frappe/desk.js
+++ b/frappe/public/js/frappe/desk.js
@@ -45,6 +45,7 @@ frappe.Application = Class.extend({
this.make_nav_bar();
this.set_favicon();
this.setup_analytics();
+ this.set_fullwidth_if_enabled();
this.setup_energy_point_listeners();
@@ -123,7 +124,7 @@ frappe.Application = Class.extend({
}
}
}
-
+ this.link_preview = new frappe.ui.LinkPreview();
},
setup_frappe_vue() {
@@ -268,7 +269,10 @@ frappe.Application = Class.extend({
refresh_notifications: function() {
var me = this;
if(frappe.session_alive && frappe.boot && frappe.boot.home_page !== 'setup-wizard') {
- return frappe.call({
+ if (this._refresh_notifications) {
+ this._refresh_notifications.abort();
+ }
+ this._refresh_notifications = frappe.call({
type: 'GET',
method: "frappe.desk.notifications.get_notifications",
callback: function(r) {
@@ -507,6 +511,10 @@ frappe.Application = Class.extend({
}
},
+ set_fullwidth_if_enabled() {
+ frappe.ui.toolbar.set_fullwidth_if_enabled();
+ },
+
show_notes: function() {
var me = this;
if(frappe.boot.notes.length) {
@@ -556,7 +564,7 @@ frappe.Application = Class.extend({
frappe.realtime.on('energy_point_alert', (message) => {
frappe.show_alert(message);
});
- }
+ },
});
frappe.get_module = function(m, default_module) {
diff --git a/frappe/public/js/frappe/feedback.js b/frappe/public/js/frappe/feedback.js
deleted file mode 100644
index 7a2e5d8156..0000000000
--- a/frappe/public/js/frappe/feedback.js
+++ /dev/null
@@ -1,102 +0,0 @@
-frappe.provide("frappe.utils")
-
-frappe.utils.Feedback = Class.extend({
- resend_feedback_request: function(doc) {
- /* resend the feedback request email */
- var args = {
- reference_name: doc.reference_name,
- reference_doctype: doc.reference_doctype,
- request: doc.feedback_request,
- }
- this.get_feedback_request_details(args, true)
- },
-
- manual_feedback_request: function(doc) {
- var me = this;
-
- var args = {
- reference_doctype: doc.doctype,
- reference_name: doc.name
- }
- if(frappe.boot.feedback_triggers[doc.doctype]) {
- var feedback_trigger = frappe.boot.feedback_triggers[doc.doctype]
- $.extend(args, { trigger: feedback_trigger })
- me.get_feedback_request_details(args, false)
- } else{
- me.make_feedback_request_dialog(args, false)
- }
- },
-
- get_feedback_request_details: function(args, is_resend) {
- var me = this;
-
- return frappe.call({
- method: "frappe.core.doctype.feedback_trigger.feedback_trigger.get_feedback_request_details",
- 'args': args,
- callback: function(r) {
- if(r.message) {
- me.make_feedback_request_dialog(r.message, is_resend)
- }
- }
- });
- },
-
- make_feedback_request_dialog: function(args, is_resend) {
- var me = this;
- var dialog = new frappe.ui.Dialog({
- title: __("{0} Feedback Request", [ is_resend? "Resend": "Send" ]),
- fields: [
- {
- "reqd": 1,
- "label": __("Recipient"),
- "fieldname": "recipients",
- "fieldtype": "Data",
- "options": "Email"
- },
- {
- "reqd": 1,
- "label": __("Subject"),
- "fieldname": "subject",
- "fieldtype": "Data"
- },
- {
- "reqd": 1,
- "label": __("Message"),
- "fieldname": "message",
- "fieldtype": "Text Editor"
- }
- ],
- });
-
- $.each(args, function(field, value){
- dialog.set_value(field, value);
- })
-
- dialog.set_primary_action(__("Send"), function() {
- $.extend(args,{ details: dialog.get_values() });
- if(!args)
- return;
-
- dialog.hide();
- me.send_feedback_request(args)
- });
-
- dialog.show();
- },
-
- send_feedback_request: function(args) {
- $.extend(args, { is_manual: true })
- return frappe.call({
- method: "frappe.core.doctype.feedback_trigger.feedback_trigger.send_feedback_request",
- 'args': args,
- freeze: true,
- callback: function(r) {
- if(r.message) {
- frappe.msgprint(__("Feedback Request for {0} is sent to {1}",
- [args.reference_name, args.details.recipients]));
- }
- }
- });
- }
-})
-
diff --git a/frappe/public/js/frappe/file_uploader/FileBrowser.vue b/frappe/public/js/frappe/file_uploader/FileBrowser.vue
new file mode 100644
index 0000000000..46bd61f120
--- /dev/null
+++ b/frappe/public/js/frappe/file_uploader/FileBrowser.vue
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
toggle_node(n)"
+ />
+
+
+
+
+
+
diff --git a/frappe/public/js/frappe/file_uploader/FilePreview.vue b/frappe/public/js/frappe/file_uploader/FilePreview.vue
new file mode 100644
index 0000000000..08c38d60f5
--- /dev/null
+++ b/frappe/public/js/frappe/file_uploader/FilePreview.vue
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frappe/public/js/frappe/file_uploader/FileUploader.vue b/frappe/public/js/frappe/file_uploader/FileUploader.vue
new file mode 100644
index 0000000000..ae7f428327
--- /dev/null
+++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue
@@ -0,0 +1,411 @@
+
+
+
+
+
+
+ {{ upload_notes }}
+
+
+
+ {{ __('Drop files here') }}
+
+
+
+
+
+ toggle_all_private(e.target.checked)">
+
+ {{ __('Make all attachments private') }}
+
+
+
+
+
+
+
+
+
+ {{ __('Upload file') }}
+
+
+ {{ __('Upload {0} files', [files.length]) }}
+
+
+
+ {{ __('Click on the lock icon to toggle public/private') }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frappe/public/js/frappe/file_uploader/TreeNode.vue b/frappe/public/js/frappe/file_uploader/TreeNode.vue
new file mode 100644
index 0000000000..ef3dbd8990
--- /dev/null
+++ b/frappe/public/js/frappe/file_uploader/TreeNode.vue
@@ -0,0 +1,32 @@
+
+
+
+
diff --git a/frappe/public/js/frappe/file_uploader/WebLink.vue b/frappe/public/js/frappe/file_uploader/WebLink.vue
new file mode 100644
index 0000000000..b0527f7d9f
--- /dev/null
+++ b/frappe/public/js/frappe/file_uploader/WebLink.vue
@@ -0,0 +1,36 @@
+
+
+
+
+
+
diff --git a/frappe/public/js/frappe/file_uploader/index.js b/frappe/public/js/frappe/file_uploader/index.js
new file mode 100644
index 0000000000..e08b952c6f
--- /dev/null
+++ b/frappe/public/js/frappe/file_uploader/index.js
@@ -0,0 +1,76 @@
+import FileUploaderComponent from './FileUploader.vue';
+
+export default class FileUploader {
+ constructor({
+ wrapper,
+ method,
+ on_success,
+ doctype,
+ docname,
+ files,
+ folder,
+ restrictions,
+ upload_notes,
+ allow_multiple,
+ as_dataurl
+ } = {}) {
+ if (!wrapper) {
+ this.make_dialog();
+ } else {
+ this.wrapper = wrapper.get ? wrapper.get(0) : wrapper;
+ }
+
+ this.$fileuploader = new Vue({
+ el: this.wrapper,
+ render: h => h(FileUploaderComponent, {
+ props: {
+ show_upload_button: !Boolean(this.dialog),
+ doctype,
+ docname,
+ method,
+ folder,
+ on_success,
+ restrictions,
+ upload_notes,
+ allow_multiple,
+ as_dataurl
+ }
+ })
+ });
+
+ this.uploader = this.$fileuploader.$children[0];
+
+ if (files && files.length) {
+ this.uploader.add_files(files);
+ }
+ }
+
+ upload_files() {
+ this.dialog && this.dialog.get_primary_btn().prop('disabled', true);
+ return this.uploader.upload_files()
+ .then(() => {
+ this.dialog && this.dialog.hide();
+ });
+ }
+
+ make_dialog() {
+ this.dialog = new frappe.ui.Dialog({
+ title: 'Upload',
+ fields: [
+ {
+ fieldtype: 'HTML',
+ fieldname: 'upload_area'
+ }
+ ],
+ primary_action_label: __('Upload'),
+ primary_action: () => this.upload_files()
+ });
+
+ this.wrapper = this.dialog.fields_dict.upload_area.$wrapper[0];
+ this.dialog.show();
+ this.dialog.$wrapper.on('hidden.bs.modal', function() {
+ $(this).data('bs.modal', null);
+ $(this).remove();
+ });
+ }
+}
diff --git a/frappe/public/js/frappe/form/controls/attach.js b/frappe/public/js/frappe/form/controls/attach.js
index 1f1eadc81d..00e9af4323 100644
--- a/frappe/public/js/frappe/form/controls/attach.js
+++ b/frappe/public/js/frappe/form/controls/attach.js
@@ -5,15 +5,15 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
.html(__("Attach"))
.prependTo(me.input_area)
.on("click", function() {
- me.onclick();
+ me.on_attach_click();
});
this.$value = $(
- `
+ `
`)
.prependTo(me.input_area)
.toggle(false);
@@ -21,7 +21,7 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
this.set_input_attributes();
this.has_input = true;
- this.$value.find(".close").on("click", function() {
+ this.$value.find(".clear-file").on("click", function() {
me.clear_attachment();
});
},
@@ -40,113 +40,28 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
this.refresh();
}
},
- onclick: function() {
- var me = this;
- if(this.doc) {
- var doc = this.doc.parent && frappe.model.get_doc(this.doc.parenttype, this.doc.parent) || this.doc;
- if (doc.__islocal) {
- frappe.msgprint(__("Please save the document before uploading."));
- return;
- }
- }
- if(!this.dialog) {
- this.dialog = new frappe.ui.Dialog({
- title: __(this.df.label || __("Upload")),
- fields: [
- {fieldtype:"HTML", fieldname:"upload_area"},
- {fieldtype:"HTML", fieldname:"or_attach", options: __("Or")},
- {fieldtype:"Select", fieldname:"select", label:__("Select from existing attachments") },
- {fieldtype:"Button", fieldname:"clear",
- label:__("Clear Attachment"), click: function() {
- me.clear_attachment();
- me.dialog.hide();
- }
- },
- ]
- });
- }
-
- this.dialog.show();
-
- this.dialog.get_field("upload_area").$wrapper.empty();
-
- // select from existing attachments
- var attachments = this.frm && this.frm.attachments.get_attachments() || [];
- var select = this.dialog.get_field("select");
- if(attachments.length) {
- attachments = $.map(attachments, function(o) { return o.file_url; });
- select.df.options = [""].concat(attachments);
- select.toggle(true);
- this.dialog.get_field("or_attach").toggle(true);
- select.refresh();
- } else {
- this.dialog.get_field("or_attach").toggle(false);
- select.toggle(false);
- }
- select.$input.val("");
-
- // show button if attachment exists
- this.dialog.get_field('clear').$wrapper.toggle(this.get_model_value() ? true : false);
-
+ on_attach_click() {
this.set_upload_options();
- frappe.upload.make(this.upload_options);
+ new frappe.ui.FileUploader(this.upload_options);
},
-
- set_upload_options: function() {
- var me = this;
- this.upload_options = {
- parent: this.dialog.get_field("upload_area").$wrapper,
- args: {},
- allow_multiple: 0,
- max_width: this.df.max_width,
- max_height: this.df.max_height,
- options: this.df.options,
- btn: this.dialog.set_primary_action(__("Upload")),
- on_no_attach: function() {
- // if no attachmemts,
- // check if something is selected
- var selected = me.dialog.get_field("select").get_value();
- if(selected) {
- me.parse_validate_and_set_in_model(selected);
- me.dialog.hide();
- me.frm.save();
- } else {
- frappe.msgprint(__("Please attach a file or set a URL"));
- }
- },
- callback: function(attachment) {
- me.on_upload_complete(attachment);
- me.dialog.hide();
- },
- onerror: function() {
- me.dialog.hide();
+ set_upload_options() {
+ let options = {
+ allow_multiple: false,
+ on_success: file => {
+ this.on_upload_complete(file);
}
};
- if ("is_private" in this.df) {
- this.upload_options.is_private = this.df.is_private;
+ if (this.frm) {
+ options.doctype = this.frm.doctype;
+ options.docname = this.frm.docname;
}
- if(this.frm) {
- this.upload_options.args = {
- from_form: 1,
- doctype: this.frm.doctype,
- docname: this.frm.docname
- };
- } else {
- this.upload_options.on_attach = function(fileobj, dataurl) {
- me.dialog.hide();
- me.fileobj = fileobj;
- me.dataurl = dataurl;
- if(me.on_attach) {
- me.on_attach();
- }
- if(me.df.on_attach) {
- me.df.on_attach(fileobj, dataurl);
- }
- me.on_upload_complete();
- };
+ if (this.df.options) {
+ Object.assign(options, this.df.options);
}
+
+ this.upload_options = options;
},
set_input: function(value, dataurl) {
@@ -168,29 +83,16 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
},
get_value: function() {
- if ( this.fileobj ) {
- if ( this.fileobj.file_url ) {
- return this.fileobj.file_url;
- } else if ( this.fileobj.filename ) {
- var dataURI = this.fileobj.filename + ',' + this.dataurl;
-
- return dataURI;
- }
- } else {
- return this.value || null;
- }
+ return this.value || null;
},
on_upload_complete: function(attachment) {
if(this.frm) {
this.parse_validate_and_set_in_model(attachment.file_url);
- this.refresh();
this.frm.attachments.update_attachment(attachment);
this.frm.doc.docstatus == 1 ? this.frm.save('Update') : this.frm.save();
- } else {
- this.value = this.get_value();
- this.refresh();
- frappe.hide_progress();
}
+ this.value = attachment.file_url;
+ this.refresh();
},
});
diff --git a/frappe/public/js/frappe/form/controls/attach_image.js b/frappe/public/js/frappe/form/controls/attach_image.js
index 4691064d8f..17e43d4683 100644
--- a/frappe/public/js/frappe/form/controls/attach_image.js
+++ b/frappe/public/js/frappe/form/controls/attach_image.js
@@ -1,70 +1,25 @@
frappe.ui.form.ControlAttachImage = frappe.ui.form.ControlAttach.extend({
- make: function() {
- var me = this;
+ make_input() {
this._super();
- this.container = $('
-
{{ _("Communication") }}
- {% include 'templates/includes/comments/comments.html' %} -