From efee03544935c1ea2cf3a6f6a092548de1202a30 Mon Sep 17 00:00:00 2001 From: Raffael Meyer Date: Tue, 26 Mar 2019 01:54:39 +0100 Subject: [PATCH 001/299] fix(integrations): complete file-api migration --- .../gsuite_templates/gsuite_templates.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.py b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.py index 83f379ee29..ad9f8145de 100644 --- a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.py +++ b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.py @@ -22,11 +22,11 @@ def create_gsuite_doc(doctype, docname, gs_template=None): json_data = doc.as_dict() filename = templ.document_name.format(**json_data) - r = run_gsuite_script('new', filename, templ.template_id, templ.destination_id, json_data) + response = run_gsuite_script('new', filename, templ.template_id, templ.destination_id, json_data) _file = frappe.get_doc({ "doctype": "File", - "file_url": r['url'], + "file_url": response['url'], "file_name": filename, "attached_to_doctype": doctype, "attached_to_name": docname, @@ -36,15 +36,15 @@ def create_gsuite_doc(doctype, docname, gs_template=None): comment = frappe.get_doc(doctype, docname).add_comment("Attachment", _("added {0}").format("{file_name}{icon}".format(**{ - "icon": ' ' if filedata.is_private else "", - "file_url": filedata.file_url.replace("#", "%23") if filedata.file_name else filedata.file_url, - "file_name": filedata.file_name or filedata.file_url + "icon": ' ' if _file.is_private else "", + "file_url": _file.file_url.replace("#", "%23") if _file.file_name else _file.file_url, + "file_name": _file.file_name or _file.file_url }))) return { - "name": filedata.name, - "file_name": filedata.file_name, - "file_url": filedata.file_url, - "is_private": filedata.is_private, + "name": _file.name, + "file_name": _file.file_name, + "file_url": _file.file_url, + "is_private": _file.is_private, "comment": comment.as_dict() if comment else {} } From ae4c24d66ed570a4ff7ed9b43e39f1ce74d41582 Mon Sep 17 00:00:00 2001 From: Raffael Meyer Date: Tue, 26 Mar 2019 05:03:29 +0100 Subject: [PATCH 002/299] feat(integrations): add autocomplete to gsuite templates --- .../gsuite_templates/gsuite_templates.js | 46 ++++++++++++++++++- .../gsuite_templates/gsuite_templates.json | 8 ++-- .../gsuite_templates/gsuite_templates.py | 43 +++++++++++++++++ 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js index d046709230..3c702b2290 100644 --- a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js +++ b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js @@ -3,6 +3,50 @@ frappe.ui.form.on('GSuite Templates', { refresh: function(frm) { - + if (frm.is_new()) { + // if doc is new, get all options immediately + set_available_docs(frm); + set_available_folders(frm); + } + }, + template_id: function(frm) { + if (!frm.is_new()) { + // if doc is NOT new, get options when selecting field + set_available_docs(frm); + } + }, + destination_id: function(frm) { + if (!frm.is_new()) { + // if doc is NOT new, get options when selecting field + set_available_folders(frm); + } } }); + +const set_available_docs = (frm) => { + frappe.call({ + method: 'frappe.integrations.doctype.gsuite_templates.gsuite_templates.get_gdrive_docs', + callback: function(res) { + // set available docs as options + set_options(frm, 'template_id', res); + } + }); +}; + +const set_available_folders = (frm) => { + frappe.call({ + method: 'frappe.integrations.doctype.gsuite_templates.gsuite_templates.get_gdrive_folders', + callback: function(res) { + // set available folders as options + set_options(frm, 'destination_id', res); + } + }); +}; + +const set_options = (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..c3fc73b8c7 100644 --- a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.json +++ b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.json @@ -81,7 +81,7 @@ "collapsible": 0, "columns": 0, "fieldname": "template_id", - "fieldtype": "Data", + "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -142,7 +142,7 @@ "collapsible": 0, "columns": 0, "fieldname": "destination_id", - "fieldtype": "Data", + "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -176,7 +176,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-05-12 16:50:08.074882", + "modified": "2019-03-26 16:50:08.074882", "modified_by": "Administrator", "module": "Integrations", "name": "GSuite Templates", @@ -212,4 +212,4 @@ "sort_order": "DESC", "track_changes": 1, "track_seen": 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') From 5cec97a0a2bc7d7b21047f8c5ada75fb3fa3c44e Mon Sep 17 00:00:00 2001 From: jibin jose Date: Fri, 5 Apr 2019 15:11:12 +0530 Subject: [PATCH 003/299] Fix social login in Python3 In Pyhton3, requests response content is in bytes type. So decoder have to handle both `str` and `bytes` to make it compatible with both python 2 and 3 --- frappe/integrations/oauth2_logins.py | 18 ++++++++++-------- frappe/utils/oauth.py | 7 ++++++- frappe/www/login.py | 10 +++++----- 3 files changed, 21 insertions(+), 14 deletions(-) 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/utils/oauth.py b/frappe/utils/oauth.py index c688bdbb5c..f5cf5d81e8 100644 --- a/frappe/utils/oauth.py +++ b/frappe/utils/oauth.py @@ -270,7 +270,7 @@ def update_oauth_user(user, data, provider): elif provider=="fairlogin" and not user.get_social_login_userid(provider): save = True user.set_social_login_userid(provider, userid=data["preferred_username"]) - + if save: user.flags.ignore_permissions = True user.flags.no_welcome_mail = True @@ -291,3 +291,8 @@ def redirect_post_login(desk_user): # the #desktop is added to prevent a facebook redirect bug frappe.local.response["location"] = "/desk#desktop" if desk_user else "/" + +def oauth_decoder(data): + if isinstance(data, bytes): + data = data.decode("utf-8") + return json.loads(data) diff --git a/frappe/www/login.py b/frappe/www/login.py index c2f83e45c3..dd51dabeab 100644 --- a/frappe/www/login.py +++ b/frappe/www/login.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe import frappe.utils -from frappe.utils.oauth import get_oauth2_authorize_url, get_oauth_keys, login_via_oauth2, login_via_oauth2_id_token, login_oauth_user as _login_oauth_user, redirect_post_login +from frappe.utils.oauth import get_oauth2_authorize_url, get_oauth_keys, login_via_oauth2, login_via_oauth2_id_token, login_oauth_user as _login_oauth_user, redirect_post_login, oauth_decoder import json from frappe import _ from frappe.auth import LoginManager @@ -56,7 +56,7 @@ def get_context(context): @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): @@ -64,15 +64,15 @@ 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_oauth_user(data=None, provider=None, state=None, email_id=None, key=None, generate_login_token=False): From 9c70a650da88dc4645930ed187e50362284ec8c4 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Fri, 5 Apr 2019 17:13:06 +0530 Subject: [PATCH 004/299] fix: get fields of doctype on change --- frappe/core/doctype/data_import/data_import.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frappe/core/doctype/data_import/data_import.js b/frappe/core/doctype/data_import/data_import.js index 6177aaf86f..9ae0a0d581 100644 --- a/frappe/core/doctype/data_import/data_import.js +++ b/frappe/core/doctype/data_import/data_import.js @@ -36,6 +36,12 @@ frappe.ui.form.on('Data Import', { }); }, + reference_doctype: function(frm){ + if (frm.doc.reference_doctype) { + frappe.model.with_doctype(frm.doc.reference_doctype); + } + }, + refresh: function(frm) { frm.disable_save(); frm.dashboard.clear_headline(); From b4ae97531385fff229d6675522320cde904c8ec8 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 11 Apr 2019 01:41:07 +0530 Subject: [PATCH 005/299] feat: Introduce new upload dialog --- frappe/core/doctype/file/file.py | 7 + frappe/handler.py | 41 +++ .../js/frappe/file_uploader/FileBrowser.vue | 136 ++++++++ .../js/frappe/file_uploader/FilePreview.vue | 120 +++++++ .../js/frappe/file_uploader/FileUploader.vue | 307 ++++++++++++++++++ .../js/frappe/file_uploader/TreeNode.vue | 32 ++ .../public/js/frappe/file_uploader/index.js | 56 ++++ frappe/public/js/frappe/misc/utils.js | 15 + frappe/public/js/frappe/upload.js | 5 + frappe/public/less/flex.less | 4 + frappe/public/less/tree.less | 24 +- 11 files changed, 734 insertions(+), 13 deletions(-) create mode 100644 frappe/public/js/frappe/file_uploader/FileBrowser.vue create mode 100644 frappe/public/js/frappe/file_uploader/FilePreview.vue create mode 100644 frappe/public/js/frappe/file_uploader/FileUploader.vue create mode 100644 frappe/public/js/frappe/file_uploader/TreeNode.vue create mode 100644 frappe/public/js/frappe/file_uploader/index.js diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index 6942b72f6a..d1a76099d2 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -919,3 +919,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/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/public/js/frappe/file_uploader/FileBrowser.vue b/frappe/public/js/frappe/file_uploader/FileBrowser.vue new file mode 100644 index 0000000000..7a34af5a6a --- /dev/null +++ b/frappe/public/js/frappe/file_uploader/FileBrowser.vue @@ -0,0 +1,136 @@ + + + + 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..6d3fac14c1 --- /dev/null +++ b/frappe/public/js/frappe/file_uploader/FilePreview.vue @@ -0,0 +1,120 @@ + + + + + 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..08daaa966d --- /dev/null +++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue @@ -0,0 +1,307 @@ + + + + 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/index.js b/frappe/public/js/frappe/file_uploader/index.js new file mode 100644 index 0000000000..46fb53bc51 --- /dev/null +++ b/frappe/public/js/frappe/file_uploader/index.js @@ -0,0 +1,56 @@ +import FileUploaderComponent from './FileUploader.vue' + +export default class FileUploader { + constructor({ wrapper, method, on_success, doctype, docname, files, folder } = {}) { + 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 + } + }) + }); + + 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(); + } +} diff --git a/frappe/public/js/frappe/misc/utils.js b/frappe/public/js/frappe/misc/utils.js index cdd8a614ad..c8544d0d9f 100644 --- a/frappe/public/js/frappe/misc/utils.js +++ b/frappe/public/js/frappe/misc/utils.js @@ -688,6 +688,21 @@ Object.assign(frappe.utils, { deep_equal(a, b) { return deep_equal(a, b); }, + + file_name_ellipsis(filename, length) { + let first_part_length = length * 2 / 3; + let last_part_length = length - first_part_length; + let parts = filename.split('.'); + let extn = parts.pop(); + let name = parts.join(''); + let first_part = name.slice(0, first_part_length); + let last_part = name.slice(-last_part_length); + if (name.length > length) { + return `${first_part}...${last_part}.${extn}`; + } else { + return filename; + } + } }); // Array de duplicate diff --git a/frappe/public/js/frappe/upload.js b/frappe/public/js/frappe/upload.js index ea32d852f3..14533fa168 100644 --- a/frappe/public/js/frappe/upload.js +++ b/frappe/public/js/frappe/upload.js @@ -1,6 +1,11 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // MIT License. See license.txt +import FileUploader from './file_uploader' + +frappe.provide('frappe.ui'); +frappe.ui.FileUploader = FileUploader; + // parent, args, callback frappe.upload = { make: function(opts) { diff --git a/frappe/public/less/flex.less b/frappe/public/less/flex.less index ed5eee1951..a5ad611683 100644 --- a/frappe/public/less/flex.less +++ b/frappe/public/less/flex.less @@ -31,6 +31,10 @@ justify-content: flex-start; } +.flex-wrap { + flex-wrap: wrap; +} + .flush-top { display: flex; justify-content: space-between; diff --git a/frappe/public/less/tree.less b/frappe/public/less/tree.less index 7df0ab4a3e..9a9a3cf567 100644 --- a/frappe/public/less/tree.less +++ b/frappe/public/less/tree.less @@ -9,7 +9,7 @@ margin: 2px 0px; } -ul.tree-children { +.tree-children { padding-left: 20px; } @@ -59,7 +59,7 @@ ul.tree-children { } @media (max-width: @screen-xs) { - ul.tree-children { + .tree-children { padding-left: 10px; } } @@ -77,7 +77,6 @@ ul.tree-children { height: ~"calc(100% - 26px)"; width: 1px; background: @border-color; - z-index: -1; } &:last-child::after { @@ -87,17 +86,16 @@ ul.tree-children { width: 3px; background: #fff; } +} - &.opened > .tree-children > .tree-node > .tree-link::before { - content: ''; - position: absolute; - width: 15px; - height: 1px; - top: 10px; - left: -11px; - z-index: -1; - background: @border-color; - } +.tree.with-skeleton .tree-children > .tree-node > .tree-link::before { + content: ''; + position: absolute; + width: 12px; + height: 1px; + top: 10px; + left: -11px; + background: @border-color; } .tree.with-skeleton.opened::before { From 7fbe08b0bcfd9596f9ea87b7e1ec3f3925d9dc3e Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 11 Apr 2019 01:42:33 +0530 Subject: [PATCH 006/299] feat: Use Feature Flag to enable new upload --- .../custom/doctype/feature_flags/__init__.py | 0 .../doctype/feature_flags/feature_flags.js | 8 ++ .../doctype/feature_flags/feature_flags.json | 93 +++++++++++++++++++ .../doctype/feature_flags/feature_flags.py | 10 ++ frappe/public/js/frappe/desk.js | 5 + .../js/frappe/form/footer/attachments.js | 32 +++++-- .../public/js/frappe/views/file/file_view.js | 23 +++-- frappe/public/js/legacy/form.js | 27 ++++-- 8 files changed, 174 insertions(+), 24 deletions(-) create mode 100644 frappe/custom/doctype/feature_flags/__init__.py create mode 100644 frappe/custom/doctype/feature_flags/feature_flags.js create mode 100644 frappe/custom/doctype/feature_flags/feature_flags.json create mode 100644 frappe/custom/doctype/feature_flags/feature_flags.py diff --git a/frappe/custom/doctype/feature_flags/__init__.py b/frappe/custom/doctype/feature_flags/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/custom/doctype/feature_flags/feature_flags.js b/frappe/custom/doctype/feature_flags/feature_flags.js new file mode 100644 index 0000000000..2c19bd218e --- /dev/null +++ b/frappe/custom/doctype/feature_flags/feature_flags.js @@ -0,0 +1,8 @@ +// Copyright (c) 2019, Frappe Technologies and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Feature Flags', { + refresh: function(frm) { + frm.set_intro(__('Enable experimental features. These features may be removed before they end up in the core.')) + } +}); diff --git a/frappe/custom/doctype/feature_flags/feature_flags.json b/frappe/custom/doctype/feature_flags/feature_flags.json new file mode 100644 index 0000000000..04a44c17ad --- /dev/null +++ b/frappe/custom/doctype/feature_flags/feature_flags.json @@ -0,0 +1,93 @@ +{ + "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2019-04-10 10:31:38.372238", + "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": "new_upload_dialog", + "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": "New Upload Dialog", + "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": 1, + "istable": 0, + "max_attachments": 0, + "modified": "2019-04-10 10:31:38.372238", + "modified_by": "Administrator", + "module": "Custom", + "name": "Feature Flags", + "name_case": "", + "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": 0, + "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", + "track_changes": 1, + "track_seen": 0, + "track_views": 0 +} \ No newline at end of file diff --git a/frappe/custom/doctype/feature_flags/feature_flags.py b/frappe/custom/doctype/feature_flags/feature_flags.py new file mode 100644 index 0000000000..03e3969775 --- /dev/null +++ b/frappe/custom/doctype/feature_flags/feature_flags.py @@ -0,0 +1,10 @@ +# -*- 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 FeatureFlags(Document): + pass diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index db85dce81f..e9b60b5269 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -47,6 +47,7 @@ frappe.Application = Class.extend({ this.setup_analytics(); this.setup_energy_point_listeners(); + this.setup_feature_flags(); frappe.ui.keys.setup(); this.set_rtl(); @@ -556,6 +557,10 @@ frappe.Application = Class.extend({ frappe.realtime.on('energy_point_alert', (message) => { frappe.show_alert(message); }); + }, + + setup_feature_flags() { + frappe.model.with_doc('Feature Flags', 'Feature Flags'); } }); diff --git a/frappe/public/js/frappe/form/footer/attachments.js b/frappe/public/js/frappe/form/footer/attachments.js index 57cd29cad8..07e8fdc4ab 100644 --- a/frappe/public/js/frappe/form/footer/attachments.js +++ b/frappe/public/js/frappe/form/footer/attachments.js @@ -63,12 +63,12 @@ frappe.ui.form.Attachments = Class.extend({ var me = this; - var $attach = $(frappe.render_template("attachment", { + var $attach = $(frappe.render_template("attachment", { "file_path": "/desk#Form/File/" + fileid, "icon": attachment.is_private ? "fa fa-lock" : "fa fa-unlock-alt", "file_name": file_name, "file_url": frappe.urllib.get_full_url(file_url) - })).insertAfter(this.attachments_label.addClass("has-attachments")); + })).insertAfter(this.attachments_label.addClass("has-attachments")); var $close = $attach.find(".close") @@ -146,13 +146,25 @@ frappe.ui.form.Attachments = Class.extend({ this.dialog.$wrapper.remove(); } - // make upload dialog - this.dialog = frappe.ui.get_upload_dialog({ - "args": me.get_args(), - "callback": function(attachment, r) { me.attachment_uploaded(attachment, r) }, - "max_width": me.frm.cscript ? me.frm.cscript.attachment_max_width : null, - "max_height": me.frm.cscript ? me.frm.cscript.attachment_max_height : null - }); + let flags = frappe.get_doc('Feature Flags'); + if (flags.new_upload_dialog) { + new frappe.ui.FileUploader({ + doctype: this.frm.doctype, + docname: this.frm.docname, + on_success: (r) => { + this.attachment_uploaded(r.message, r); + } + }); + } else { + // make upload dialog + this.dialog = frappe.ui.get_upload_dialog({ + "args": me.get_args(), + "callback": function(attachment, r) { me.attachment_uploaded(attachment, r) }, + "max_width": me.frm.cscript ? me.frm.cscript.attachment_max_width : null, + "max_height": me.frm.cscript ? me.frm.cscript.attachment_max_height : null + }); + } + }, get_args: function() { return { @@ -263,7 +275,7 @@ frappe.ui.get_upload_dialog = function(opts){ dialog.show(); var upload_area = $('
').prependTo(dialog.body); - + frappe.upload.make({ parent: upload_area, diff --git a/frappe/public/js/frappe/views/file/file_view.js b/frappe/public/js/frappe/views/file/file_view.js index 4a37fae166..a1eaedcac1 100644 --- a/frappe/public/js/frappe/views/file/file_view.js +++ b/frappe/public/js/frappe/views/file/file_view.js @@ -325,13 +325,22 @@ frappe.views.FileView = class FileView extends frappe.views.ListView { } e.stopPropagation(); e.preventDefault(); - frappe.upload.make({ - files: dataTransfer.files, - "args": { - "folder": this.current_folder, - "from_form": 1 - } - }); + + let flags = frappe.get_doc('Feature Flags'); + if (flags.new_upload_dialog) { + new frappe.ui.FileUploader({ + files: dataTransfer.files, + folder: this.current_folder + }); + } else { + frappe.upload.make({ + files: dataTransfer.files, + "args": { + "folder": this.current_folder, + "from_form": 1 + } + }); + } }); } diff --git a/frappe/public/js/legacy/form.js b/frappe/public/js/legacy/form.js index c63c9cb4a0..c5da20b39e 100644 --- a/frappe/public/js/legacy/form.js +++ b/frappe/public/js/legacy/form.js @@ -142,13 +142,26 @@ _f.Frm.prototype.setup_drag_drop = function() { throw "attach error"; } - frappe.upload.make({ - args: me.attachments.get_args(), - files: dataTransfer.files, - callback: function(attachment, r) { - me.attachments.attachment_uploaded(attachment, r); - } - }); + let flags = frappe.get_doc('Feature Flags'); + + if (flags.new_upload_dialog) { + new frappe.ui.FileUploader({ + doctype: me.doctype, + docname: me.docname, + files: dataTransfer.files, + on_success(r) { + me.attachments.attachment_uploaded(r.message, r); + } + }); + } else { + frappe.upload.make({ + args: me.attachments.get_args(), + files: dataTransfer.files, + callback: function(attachment, r) { + me.attachments.attachment_uploaded(attachment, r); + } + }); + } }); }; From 8ff5c75d3334675b4ea197eb18f08a8d2cc55dcc Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 11 Apr 2019 10:36:22 +0530 Subject: [PATCH 007/299] fix: Missing semicolon --- frappe/custom/doctype/feature_flags/feature_flags.js | 2 +- frappe/public/js/frappe/file_uploader/index.js | 2 +- frappe/public/js/frappe/upload.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/custom/doctype/feature_flags/feature_flags.js b/frappe/custom/doctype/feature_flags/feature_flags.js index 2c19bd218e..622a995230 100644 --- a/frappe/custom/doctype/feature_flags/feature_flags.js +++ b/frappe/custom/doctype/feature_flags/feature_flags.js @@ -3,6 +3,6 @@ frappe.ui.form.on('Feature Flags', { refresh: function(frm) { - frm.set_intro(__('Enable experimental features. These features may be removed before they end up in the core.')) + frm.set_intro(__('Enable experimental features. These features may be removed before they end up in the core.')); } }); diff --git a/frappe/public/js/frappe/file_uploader/index.js b/frappe/public/js/frappe/file_uploader/index.js index 46fb53bc51..084bac5664 100644 --- a/frappe/public/js/frappe/file_uploader/index.js +++ b/frappe/public/js/frappe/file_uploader/index.js @@ -1,4 +1,4 @@ -import FileUploaderComponent from './FileUploader.vue' +import FileUploaderComponent from './FileUploader.vue'; export default class FileUploader { constructor({ wrapper, method, on_success, doctype, docname, files, folder } = {}) { diff --git a/frappe/public/js/frappe/upload.js b/frappe/public/js/frappe/upload.js index 14533fa168..e32c3f92df 100644 --- a/frappe/public/js/frappe/upload.js +++ b/frappe/public/js/frappe/upload.js @@ -1,7 +1,7 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // MIT License. See license.txt -import FileUploader from './file_uploader' +import FileUploader from './file_uploader'; frappe.provide('frappe.ui'); frappe.ui.FileUploader = FileUploader; From d87e0bb1d5f31976c78af3d280f7e42eb2695664 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 11 Apr 2019 12:51:48 +0530 Subject: [PATCH 008/299] fix: Add file type and size restrictions --- .../js/frappe/file_uploader/FileUploader.vue | 77 +++++++++++++++---- .../public/js/frappe/file_uploader/index.js | 16 +++- 2 files changed, 78 insertions(+), 15 deletions(-) diff --git a/frappe/public/js/frappe/file_uploader/FileUploader.vue b/frappe/public/js/frappe/file_uploader/FileUploader.vue index 08daaa966d..e52919934e 100644 --- a/frappe/public/js/frappe/file_uploader/FileUploader.vue +++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue @@ -20,6 +20,7 @@ ref="file_input" @change="on_file_input" :multiple="multiple_files" + :accept="restrictions.allowed_file_types.join(', ')" > {{ __('or choose an') }} @@ -124,6 +125,16 @@ export default { }, on_success: { default: null + }, + restrictions: { + default: () => ({ + max_file_size: null, // 2048 -> 2KB + max_number_of_files: null, + allowed_file_types: [] // ['image/*', 'video/*', '.jpg', '.gif', '.pdf'] + }) + }, + upload_notes: { + default: null // "Images or video, upto 2MB" } }, components: { @@ -185,21 +196,61 @@ export default { }); }, add_files(file_array) { - let files = Array.from(file_array).map(file => { - let is_image = file.type.startsWith('image'); - return { - file_obj: file, - name: file.name, - doc: null, - progress: 0, - total: 0, - failed: false, - uploading: false, - private: !is_image - } - }); + let files = Array.from(file_array) + .filter(this.check_restrictions) + .map(file => { + let is_image = file.type.startsWith('image'); + return { + file_obj: file, + name: file.name, + doc: null, + progress: 0, + total: 0, + failed: false, + uploading: false, + private: !is_image + } + }); this.files = this.files.concat(files); }, + check_restrictions(file) { + let { max_file_size, allowed_file_types } = this.restrictions; + + let mime_type = file.type; + let extension = '.' + file.name.split('.').pop(); + + let is_correct_type = true; + let valid_file_size = true; + + if (allowed_file_types) { + is_correct_type = allowed_file_types.some((type) => { + // is this is a mime-type + if (type.includes('/')) { + if (!file.type) return false; + return file.type.match(type); + } + + // otherwise this is likely an extension + if (type[0] === '.') { + return file.name.endsWith(type); + } + return false; + }); + } + + if (max_file_size && file.size != null) { + valid_file_size = file.size < max_file_size; + } + + if (!is_correct_type) { + console.warn('File skipped because of invalid file type', file); + } + if (!valid_file_size) { + console.warn('File skipped because of invalid file size', file.size, file); + } + + return is_correct_type && valid_file_size; + }, upload_files() { if (this.show_file_browser) { let selected_file = this.$refs.file_browser.selected_node; diff --git a/frappe/public/js/frappe/file_uploader/index.js b/frappe/public/js/frappe/file_uploader/index.js index 084bac5664..c930aaa3b6 100644 --- a/frappe/public/js/frappe/file_uploader/index.js +++ b/frappe/public/js/frappe/file_uploader/index.js @@ -1,7 +1,17 @@ import FileUploaderComponent from './FileUploader.vue'; export default class FileUploader { - constructor({ wrapper, method, on_success, doctype, docname, files, folder } = {}) { + constructor({ + wrapper, + method, + on_success, + doctype, + docname, + files, + folder, + restrictions, + upload_notes + } = {}) { if (!wrapper) { this.make_dialog(); } else { @@ -17,7 +27,9 @@ export default class FileUploader { docname, method, folder, - on_success + on_success, + restrictions, + upload_notes } }) }); From 1ef753a37fe1de3e54f0e1e997ff52c0552c327f Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 11 Apr 2019 12:51:58 +0530 Subject: [PATCH 009/299] fix: Upload via web link --- .../js/frappe/file_uploader/FileBrowser.vue | 6 +-- .../js/frappe/file_uploader/FileUploader.vue | 45 ++++++++++++++----- .../js/frappe/file_uploader/WebLink.vue | 36 +++++++++++++++ 3 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 frappe/public/js/frappe/file_uploader/WebLink.vue diff --git a/frappe/public/js/frappe/file_uploader/FileBrowser.vue b/frappe/public/js/frappe/file_uploader/FileBrowser.vue index 7a34af5a6a..46bd61f120 100644 --- a/frappe/public/js/frappe/file_uploader/FileBrowser.vue +++ b/frappe/public/js/frappe/file_uploader/FileBrowser.vue @@ -1,12 +1,11 @@ + + From 5d14cdc44affcec2ce16243bcd5addc3ca48a9d9 Mon Sep 17 00:00:00 2001 From: Raffael Meyer Date: Fri, 12 Apr 2019 19:56:26 +0200 Subject: [PATCH 010/299] put functions in scope --- .../gsuite_templates/gsuite_templates.js | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js index 3c702b2290..4b383bbb26 100644 --- a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js +++ b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js @@ -5,48 +5,49 @@ frappe.ui.form.on('GSuite Templates', { refresh: function(frm) { if (frm.is_new()) { // if doc is new, get all options immediately - set_available_docs(frm); - set_available_folders(frm); + frm.trigger('set_available_docs'); + frm.trigger('set_available_folders'); } }, template_id: function(frm) { if (!frm.is_new()) { // if doc is NOT new, get options when selecting field - set_available_docs(frm); + frm.trigger('set_available_docs'); } }, destination_id: function(frm) { if (!frm.is_new()) { // if doc is NOT new, get options when selecting field - set_available_folders(frm); + 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 + frm.trigger('set_options', '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 + frm.trigger('set_options', 'destination_id', res); + } + }); + }, + set_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); } }); -const set_available_docs = (frm) => { - frappe.call({ - method: 'frappe.integrations.doctype.gsuite_templates.gsuite_templates.get_gdrive_docs', - callback: function(res) { - // set available docs as options - set_options(frm, 'template_id', res); - } - }); -}; -const set_available_folders = (frm) => { - frappe.call({ - method: 'frappe.integrations.doctype.gsuite_templates.gsuite_templates.get_gdrive_folders', - callback: function(res) { - // set available folders as options - set_options(frm, 'destination_id', res); - } - }); -}; - -const set_options = (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); -}; From 7bf098cd780504883912203c3b6cffe186ed957d Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 13 Apr 2019 11:14:01 +0530 Subject: [PATCH 011/299] fix: Pass file_doc to on_success --- frappe/public/js/frappe/file_uploader/FileUploader.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/file_uploader/FileUploader.vue b/frappe/public/js/frappe/file_uploader/FileUploader.vue index f585b587bc..4d48ce5e32 100644 --- a/frappe/public/js/frappe/file_uploader/FileUploader.vue +++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue @@ -236,7 +236,7 @@ export default { let is_correct_type = true; let valid_file_size = true; - if (allowed_file_types) { + if (allowed_file_types.length) { is_correct_type = allowed_file_types.some((type) => { // is this is a mime-type if (type.includes('/')) { @@ -321,20 +321,20 @@ export default { if (xhr.readyState == XMLHttpRequest.DONE) { if (xhr.status === 200) { let r = null; - let doc = null; + let file_doc = null; try { r = JSON.parse(xhr.responseText); if (r.message.doctype === 'File') { - doc = r.message; + file_doc = r.message; } } catch(e) { r = xhr.responseText; } - file.doc = doc; + file.doc = file_doc; if (this.on_success) { - this.on_success(r); + this.on_success(file_doc, r); } } else { file.failed = true; From 6c576d9793c29328dd9f511f7e7c319dd305a291 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 13 Apr 2019 14:44:25 +0530 Subject: [PATCH 012/299] refactor: Rename multiple_files to allow_multiple --- frappe/public/js/frappe/file_uploader/FileUploader.vue | 6 +++--- frappe/public/js/frappe/file_uploader/index.js | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/file_uploader/FileUploader.vue b/frappe/public/js/frappe/file_uploader/FileUploader.vue index 4d48ce5e32..2325f60cf4 100644 --- a/frappe/public/js/frappe/file_uploader/FileUploader.vue +++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue @@ -19,7 +19,7 @@ class="hidden" ref="file_input" @change="on_file_input" - :multiple="multiple_files" + :multiple="allow_multiple" :accept="restrictions.allowed_file_types.join(', ')" > @@ -123,7 +123,7 @@ export default { show_upload_button: { default: true }, - multiple_files: { + allow_multiple: { default: true }, doctype: { @@ -168,7 +168,7 @@ export default { }, watch: { files(newvalue, oldvalue) { - if (!this.multiple_files && newvalue.length > 1) { + if (!this.allow_multiple && newvalue.length > 1) { this.files = [newvalue[newvalue.length - 1]]; } } diff --git a/frappe/public/js/frappe/file_uploader/index.js b/frappe/public/js/frappe/file_uploader/index.js index c930aaa3b6..9bac74f023 100644 --- a/frappe/public/js/frappe/file_uploader/index.js +++ b/frappe/public/js/frappe/file_uploader/index.js @@ -10,7 +10,8 @@ export default class FileUploader { files, folder, restrictions, - upload_notes + upload_notes, + allow_multiple } = {}) { if (!wrapper) { this.make_dialog(); @@ -29,7 +30,8 @@ export default class FileUploader { folder, on_success, restrictions, - upload_notes + upload_notes, + allow_multiple } }) }); From 93d6ec08ebb9d4f7d857d2f2d77dc7843ae25f01 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 13 Apr 2019 14:44:59 +0530 Subject: [PATCH 013/299] fix: Replace old upload with new FileUploader --- frappe/core/doctype/file/file.py | 7 ++- frappe/public/js/frappe/chat.js | 9 +-- .../js/frappe/form/footer/attachments.js | 28 +++------ .../public/js/frappe/views/communication.js | 43 ++++++-------- .../public/js/frappe/views/file/file_view.js | 57 +++++++------------ frappe/public/js/frappe/views/interaction.js | 51 +++++++---------- frappe/public/js/legacy/form.js | 28 +++------ 7 files changed, 83 insertions(+), 140 deletions(-) diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index d1a76099d2..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() 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/form/footer/attachments.js b/frappe/public/js/frappe/form/footer/attachments.js index 07e8fdc4ab..7ffd6a3c2c 100644 --- a/frappe/public/js/frappe/form/footer/attachments.js +++ b/frappe/public/js/frappe/form/footer/attachments.js @@ -146,25 +146,13 @@ frappe.ui.form.Attachments = Class.extend({ this.dialog.$wrapper.remove(); } - let flags = frappe.get_doc('Feature Flags'); - if (flags.new_upload_dialog) { - new frappe.ui.FileUploader({ - doctype: this.frm.doctype, - docname: this.frm.docname, - on_success: (r) => { - this.attachment_uploaded(r.message, r); - } - }); - } else { - // make upload dialog - this.dialog = frappe.ui.get_upload_dialog({ - "args": me.get_args(), - "callback": function(attachment, r) { me.attachment_uploaded(attachment, r) }, - "max_width": me.frm.cscript ? me.frm.cscript.attachment_max_width : null, - "max_height": me.frm.cscript ? me.frm.cscript.attachment_max_height : null - }); - } - + new frappe.ui.FileUploader({ + doctype: this.frm.doctype, + docname: this.frm.docname, + on_success: (file_doc) => { + this.attachment_uploaded(file_doc); + } + }); }, get_args: function() { return { @@ -173,7 +161,7 @@ frappe.ui.form.Attachments = Class.extend({ docname: this.frm.docname, } }, - attachment_uploaded: function(attachment, r) { + attachment_uploaded: function(attachment) { this.dialog && this.dialog.hide(); this.update_attachment(attachment); this.frm.reload_docinfo(); diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js index 027f1fd1b7..15d456bff0 100755 --- a/frappe/public/js/frappe/views/communication.js +++ b/frappe/public/js/frappe/views/communication.js @@ -359,33 +359,25 @@ frappe.views.CommunicationComposer = Class.extend({ var fields = this.dialog.fields_dict; var attach = $(fields.select_attachments.wrapper); - var me = this - if (!me.attachments){ - me.attachments = [] + if (!this.attachments) { + this.attachments = [] } - var args = { - args: { - from_form: 1, - folder:"Home/Attachments" - }, - callback: function(attachment, r) { me.attachments.push(attachment); }, - max_width: null, - max_height: null + let args = { + folder: 'Home/Attachments', + on_success: attachment => this.attachments.push(attachment) }; - if(me.frm) { + if(this.frm) { args = { - args: (me.frm.attachments.get_args - ? me.frm.attachments.get_args() - : { from_form: 1,folder:"Home/Attachments" }), - callback: function (attachment, r) { - me.frm.attachments.attachment_uploaded(attachment, r) - }, - max_width: me.frm.cscript ? me.frm.cscript.attachment_max_width : null, - max_height: me.frm.cscript ? me.frm.cscript.attachment_max_height : null + doctype: this.frm.doctype, + docname: this.frm.docname, + folder: 'Home/Attachments', + on_success: attachment => { + this.frm.attachments.attachment_uploaded(attachment); + this.render_attach(); + } } - } $("
" @@ -393,11 +385,10 @@ frappe.views.CommunicationComposer = Class.extend({

\ " +__("Add Attachment")+"

").appendTo(attach.empty()) - attach.find(".add-more-attachments a").on('click',this,function() { - me.upload = frappe.ui.get_upload_dialog(args); - }) - me.render_attach() - + attach + .find(".add-more-attachments a") + .on('click',() => new frappe.ui.FileUploader(args)); + this.render_attach(); }, render_attach:function(){ var fields = this.dialog.fields_dict; diff --git a/frappe/public/js/frappe/views/file/file_view.js b/frappe/public/js/frappe/views/file/file_view.js index a1eaedcac1..8d4e47a65c 100644 --- a/frappe/public/js/frappe/views/file/file_view.js +++ b/frappe/public/js/frappe/views/file/file_view.js @@ -103,25 +103,20 @@ frappe.views.FileView = class FileView extends frappe.views.ListView { { label: __('Import Zip'), action: () => { - // make upload dialog - frappe.ui.get_upload_dialog({ - args: { - folder: this.current_folder, - from_form: 1 + new frappe.ui.FileUploader({ + folder: this.current_folder, + restrictions: { + allowed_file_types: ['.zip'] }, - callback: (attachment, r) => { - frappe.call({ - method: 'frappe.core.doctype.file.file.unzip_file', - args: { - name: r.message.name, - }, - callback: function (r) { - if(r.exc) { - frappe.msgprint(__('Error in uploading files' + r.exc)); + on_success: file => { + frappe.show_alert(__('Unzipping files...')); + frappe.call('frappe.core.doctype.file.file.unzip_file', { name: file.name }) + .then((r) => { + if (r.message) { + frappe.show_alert(__('Unzipped {0} files', [r.message])); } - } - }); - }, + }); + } }); } } @@ -302,12 +297,9 @@ frappe.views.FileView = class FileView extends frappe.views.ListView { } make_new_doc() { - frappe.ui.get_upload_dialog({ - "args": { - "folder": this.current_folder, - "from_form": 1 - }, - callback:() => this.refresh() + new frappe.ui.FileUploader({ + folder: this.current_folder, + on_success: () => this.refresh() }); } @@ -326,21 +318,10 @@ frappe.views.FileView = class FileView extends frappe.views.ListView { e.stopPropagation(); e.preventDefault(); - let flags = frappe.get_doc('Feature Flags'); - if (flags.new_upload_dialog) { - new frappe.ui.FileUploader({ - files: dataTransfer.files, - folder: this.current_folder - }); - } else { - frappe.upload.make({ - files: dataTransfer.files, - "args": { - "folder": this.current_folder, - "from_form": 1 - } - }); - } + new frappe.ui.FileUploader({ + files: dataTransfer.files, + folder: this.current_folder + }); }); } diff --git a/frappe/public/js/frappe/views/interaction.js b/frappe/public/js/frappe/views/interaction.js index 36de959a6a..25490446e2 100644 --- a/frappe/public/js/frappe/views/interaction.js +++ b/frappe/public/js/frappe/views/interaction.js @@ -115,50 +115,39 @@ frappe.views.InteractionComposer = class InteractionComposer { } setup_attach() { - let fields = this.dialog.fields_dict; - let attach = $(fields.select_attachments.wrapper); + var fields = this.dialog.fields_dict; + var attach = $(fields.select_attachments.wrapper); - let me = this; - if (!me.attachments){ - me.attachments = []; + if (!this.attachments) { + this.attachments = [] } let args = { - args: { - from_form: 1, - folder:"Home/Attachments" - }, - callback: function(attachment){ - me.attachments.push(attachment); - }, - max_width: null, - max_height: null + folder: 'Home/Attachments', + on_success: attachment => this.attachments.push(attachment) }; - if(me.frm) { + if (this.frm) { args = { - args: (me.frm.attachments.get_args - ? me.frm.attachments.get_args() - : { from_form: 1,folder:"Home/Attachments" }), - callback: function(attachment, r){ - me.frm.attachments.attachment_uploaded(attachment, r); - }, - max_width: me.frm.cscript ? me.frm.cscript.attachment_max_width : null, - max_height: me.frm.cscript ? me.frm.cscript.attachment_max_height : null - }; - + doctype: this.frm.doctype, + docname: this.frm.docname, + folder: 'Home/Attachments', + on_success: attachment => { + this.frm.attachments.attachment_uploaded(attachment); + this.render_attach(); + } + } } $("
" +__("Select Attachments")+"
\

\ " - +__("Add Attachment")+"

").appendTo(attach.empty()); - attach.find(".add-more-attachments a").on('click',this,function() { - me.upload = frappe.ui.get_upload_dialog(args); - }); - me.render_attach(); - + +__("Add Attachment")+"

").appendTo(attach.empty()) + attach + .find(".add-more-attachments a") + .on('click',() => new frappe.ui.FileUploader(args)); + this.render_attach(); } render_attach(){ diff --git a/frappe/public/js/legacy/form.js b/frappe/public/js/legacy/form.js index c5da20b39e..4c89e05a6b 100644 --- a/frappe/public/js/legacy/form.js +++ b/frappe/public/js/legacy/form.js @@ -142,26 +142,14 @@ _f.Frm.prototype.setup_drag_drop = function() { throw "attach error"; } - let flags = frappe.get_doc('Feature Flags'); - - if (flags.new_upload_dialog) { - new frappe.ui.FileUploader({ - doctype: me.doctype, - docname: me.docname, - files: dataTransfer.files, - on_success(r) { - me.attachments.attachment_uploaded(r.message, r); - } - }); - } else { - frappe.upload.make({ - args: me.attachments.get_args(), - files: dataTransfer.files, - callback: function(attachment, r) { - me.attachments.attachment_uploaded(attachment, r); - } - }); - } + new frappe.ui.FileUploader({ + doctype: me.doctype, + docname: me.docname, + files: dataTransfer.files, + on_success(file_doc) { + me.attachments.attachment_uploaded(file_doc); + } + }); }); }; From 15b9421365007afe54aeb7a999db65dd65659878 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 13 Apr 2019 14:45:28 +0530 Subject: [PATCH 014/299] fix: Refactor Attach controls to use new FileUploader --- .../public/js/frappe/form/controls/attach.js | 121 +++--------------- .../js/frappe/form/controls/attach_image.js | 79 +++--------- frappe/public/less/form.less | 14 +- 3 files changed, 41 insertions(+), 173 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/attach.js b/frappe/public/js/frappe/form/controls/attach.js index 1f1eadc81d..694bfb6fb3 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) { 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 = $('
').insertAfter($(this.wrapper)); - $(this.wrapper).detach(); - this.container.attr('data-fieldtype', this.df.fieldtype).append(this.wrapper); - if(this.df.align === 'center') { - this.container.addClass("flex-justify-center"); - } else if (this.df.align === 'right') { - this.container.addClass("flex-justify-end"); - } - - this.img_wrapper = $('
\ -
') - .appendTo(this.wrapper); - - this.img_container = $(`
`); - this.img = $(``) - .appendTo(this.img_container); - - this.img_overlay = $(`
- Change -
`).appendTo(this.img_container); - - this.remove_image_link = $('Remove'); - - this.img_wrapper.append(this.img_container).append(this.remove_image_link); - // this.img.toggle(false); - // this.img_overlay.toggle(false); - this.img_container.toggle(false); - this.remove_image_link.toggle(false); - - // propagate click to Attach button - this.img_wrapper.find(".missing-image").on("click", function() { me.$input.click(); }); - this.img_container.on("click", function() { me.$input.click(); }); - this.remove_image_link.on("click", function() { me.$value.find(".close").click(); }); - - this.set_image(); - }, - refresh_input: function() { - this._super(); - $(this.wrapper).find('.btn-attach').addClass('hidden'); - this.set_image(); - if(this.get_status()=="Read") { - $(this.disp_area).toggle(false); - } - }, - set_image: function() { - if(this.get_value()) { - $(this.img_wrapper).find(".missing-image").toggle(false); - // this.img.attr("src", this.dataurl ? this.dataurl : this.value).toggle(true); - // this.img_overlay.toggle(true); - this.img.attr("src", this.dataurl ? this.dataurl : this.value); - this.img_container.toggle(true); - this.remove_image_link.toggle(true); - } else { - $(this.img_wrapper).find(".missing-image").toggle(true); - // this.img.toggle(false); - // this.img_overlay.toggle(false); - this.img_container.toggle(false); - this.remove_image_link.toggle(false); - } + let $file_link = this.$value.find('.attached-file-link'); + $file_link.popover({ + trigger: 'hover', + placement: 'top', + content: () => { + return `
+ +
`; + }, + html: true + }); }, set_upload_options() { this._super(); - this.upload_options.restrict_to_images = true; + this.upload_options.restrictions = {}; + this.upload_options.restrictions.allowed_file_types = ['image/*']; } }); diff --git a/frappe/public/less/form.less b/frappe/public/less/form.less index b09143f5f5..ada389edac 100644 --- a/frappe/public/less/form.less +++ b/frappe/public/less/form.less @@ -936,16 +936,14 @@ body[data-route^="Form/Communication"] textarea[data-fieldname="subject"] { height: 80px !important; } -.frappe-control[data-fieldtype="Attach"] { +.frappe-control[data-fieldtype="Attach"], .frappe-control[data-fieldtype="Attach Image"] { .attached-file { position: relative; - margin-top: 5px; - - .close { - position: absolute; - top: 0; - right: 0; - } + padding: 6px 10px; + background: @light-bg; + border-radius: 4px; + border: 1px solid @border-color; + font-size: @text-medium; } } From 04be929a90f38a5a21ceff98267e97fa75d94b6e Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 13 Apr 2019 14:52:01 +0530 Subject: [PATCH 015/299] fix: Remove Feature Flag settings --- .../custom/doctype/feature_flags/__init__.py | 0 .../doctype/feature_flags/feature_flags.js | 8 -- .../doctype/feature_flags/feature_flags.json | 93 ------------------- .../doctype/feature_flags/feature_flags.py | 10 -- frappe/public/js/frappe/desk.js | 5 - 5 files changed, 116 deletions(-) delete mode 100644 frappe/custom/doctype/feature_flags/__init__.py delete mode 100644 frappe/custom/doctype/feature_flags/feature_flags.js delete mode 100644 frappe/custom/doctype/feature_flags/feature_flags.json delete mode 100644 frappe/custom/doctype/feature_flags/feature_flags.py diff --git a/frappe/custom/doctype/feature_flags/__init__.py b/frappe/custom/doctype/feature_flags/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/frappe/custom/doctype/feature_flags/feature_flags.js b/frappe/custom/doctype/feature_flags/feature_flags.js deleted file mode 100644 index 622a995230..0000000000 --- a/frappe/custom/doctype/feature_flags/feature_flags.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2019, Frappe Technologies and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Feature Flags', { - refresh: function(frm) { - frm.set_intro(__('Enable experimental features. These features may be removed before they end up in the core.')); - } -}); diff --git a/frappe/custom/doctype/feature_flags/feature_flags.json b/frappe/custom/doctype/feature_flags/feature_flags.json deleted file mode 100644 index 04a44c17ad..0000000000 --- a/frappe/custom/doctype/feature_flags/feature_flags.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2019-04-10 10:31:38.372238", - "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": "new_upload_dialog", - "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": "New Upload Dialog", - "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": 1, - "istable": 0, - "max_attachments": 0, - "modified": "2019-04-10 10:31:38.372238", - "modified_by": "Administrator", - "module": "Custom", - "name": "Feature Flags", - "name_case": "", - "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": 0, - "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", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/frappe/custom/doctype/feature_flags/feature_flags.py b/frappe/custom/doctype/feature_flags/feature_flags.py deleted file mode 100644 index 03e3969775..0000000000 --- a/frappe/custom/doctype/feature_flags/feature_flags.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- 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 FeatureFlags(Document): - pass diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index e9b60b5269..6ff78a1e6a 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -47,7 +47,6 @@ frappe.Application = Class.extend({ this.setup_analytics(); this.setup_energy_point_listeners(); - this.setup_feature_flags(); frappe.ui.keys.setup(); this.set_rtl(); @@ -558,10 +557,6 @@ frappe.Application = Class.extend({ frappe.show_alert(message); }); }, - - setup_feature_flags() { - frappe.model.with_doc('Feature Flags', 'Feature Flags'); - } }); frappe.get_module = function(m, default_module) { From a5c6dbf3eddae380312642d472865d3eca7f6a83 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 13 Apr 2019 15:29:32 +0530 Subject: [PATCH 016/299] test: Add UI test for FileUploader --- cypress/integration/file_uploader.js | 58 ++++++++++++++++++++++++++++ cypress/support/commands.js | 10 +++++ package.json | 1 + yarn.lock | 6 ++- 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 cypress/integration/file_uploader.js diff --git a/cypress/integration/file_uploader.js b/cypress/integration/file_uploader.js new file mode 100644 index 0000000000..dff2d11427 --- /dev/null +++ b/cypress/integration/file_uploader.js @@ -0,0 +1,58 @@ +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); + }); + }); + + 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'); + }); + + 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'); + }); +}); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 8c2156e9f4..232547a75a 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 @@ -75,3 +76,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/package.json b/package.json index 3b5decfc35..41156f2fb3 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "babel-runtime": "^6.26.0", "chalk": "^2.3.2", "cypress": "^3.1.1", + "cypress-file-upload": "^3.1.0", "less": "^3.0.4", "node-sass": "^4.11.0", "rollup": "^1.2.2", diff --git a/yarn.lock b/yarn.lock index bf1904c5c1..788b469f97 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1124,6 +1124,11 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" +cypress-file-upload@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-3.1.0.tgz#9da7ed60619631231bd2caaf9844874e7cec6f69" + integrity sha512-zJh6Qwh+BZz6j3oCxMgRmfSsHJ+vSm2FrsZ1j/hG3s1O+6UPhOCDGeJucMUGBivWb1IsHrLKJP4LfgHSooPZHw== + cypress@^3.1.1: version "3.1.5" resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.1.5.tgz#5227b2ce9306c47236d29e703bad9055d7218042" @@ -1715,7 +1720,6 @@ forwarded@~0.1.2: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= - fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" From 93523df7d6e2ef6a11b4079cafbb2d6e6ac507fd Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 13 Apr 2019 15:49:21 +0530 Subject: [PATCH 017/299] style: Missing semicolon --- cypress/integration/file_uploader.js | 2 +- cypress/support/commands.js | 2 +- frappe/public/js/frappe/views/communication.js | 2 +- frappe/public/js/frappe/views/interaction.js | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cypress/integration/file_uploader.js b/cypress/integration/file_uploader.js index dff2d11427..8dd0f22ee9 100644 --- a/cypress/integration/file_uploader.js +++ b/cypress/integration/file_uploader.js @@ -6,7 +6,7 @@ context('FileUploader', () => { function open_upload_dialog() { cy.window().its('frappe').then(frappe => { - new frappe.ui.FileUploader() + new frappe.ui.FileUploader(); }); } diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 232547a75a..010c0242f5 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -1,4 +1,4 @@ -import 'cypress-file-upload' +import 'cypress-file-upload'; // *********************************************** // This example commands.js shows you how to // create various custom commands and overwrite diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js index 15d456bff0..7d90d80d5f 100755 --- a/frappe/public/js/frappe/views/communication.js +++ b/frappe/public/js/frappe/views/communication.js @@ -360,7 +360,7 @@ frappe.views.CommunicationComposer = Class.extend({ var attach = $(fields.select_attachments.wrapper); if (!this.attachments) { - this.attachments = [] + this.attachments = []; } let args = { diff --git a/frappe/public/js/frappe/views/interaction.js b/frappe/public/js/frappe/views/interaction.js index 25490446e2..458f4c8dc1 100644 --- a/frappe/public/js/frappe/views/interaction.js +++ b/frappe/public/js/frappe/views/interaction.js @@ -119,7 +119,7 @@ frappe.views.InteractionComposer = class InteractionComposer { var attach = $(fields.select_attachments.wrapper); if (!this.attachments) { - this.attachments = [] + this.attachments = []; } let args = { @@ -136,14 +136,14 @@ frappe.views.InteractionComposer = class InteractionComposer { this.frm.attachments.attachment_uploaded(attachment); this.render_attach(); } - } + }; } $("
" +__("Select Attachments")+"
\

\ " - +__("Add Attachment")+"

").appendTo(attach.empty()) + +__("Add Attachment")+"

").appendTo(attach.empty()); attach .find(".add-more-attachments a") .on('click',() => new frappe.ui.FileUploader(args)); From 5c48d2c24fc35b87be3ac36b5943a40b659295ad Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 13 Apr 2019 22:14:09 +0530 Subject: [PATCH 018/299] fix: Force click web link --- cypress/integration/file_uploader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/integration/file_uploader.js b/cypress/integration/file_uploader.js index 8dd0f22ee9..de2854261f 100644 --- a/cypress/integration/file_uploader.js +++ b/cypress/integration/file_uploader.js @@ -47,7 +47,7 @@ context('FileUploader', () => { it('should accept web links', () => { open_upload_dialog(); - cy.get_open_dialog().find('a:contains("web link")').click(); + cy.get_open_dialog().find('a:contains("web link")').click({ force: true }); 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'); From 6f0ba6cf541496439ce63292560963e28712c3a6 Mon Sep 17 00:00:00 2001 From: Raffael Meyer Date: Sat, 13 Apr 2019 23:59:24 +0200 Subject: [PATCH 019/299] function out of scope, but with unique name --- .../gsuite_templates/gsuite_templates.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js index 4b383bbb26..2721a9746f 100644 --- a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js +++ b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js @@ -27,7 +27,7 @@ frappe.ui.form.on('GSuite Templates', { method: 'frappe.integrations.doctype.gsuite_templates.gsuite_templates.get_gdrive_docs', callback: function(res) { // set available documents as options - frm.trigger('set_options', 'template_id', res); + set_gsuite_template_options(frm, 'template_id', res); } }); }, @@ -37,17 +37,17 @@ frappe.ui.form.on('GSuite Templates', { method: 'frappe.integrations.doctype.gsuite_templates.gsuite_templates.get_gdrive_folders', callback: function(res) { // set available folders as options - frm.trigger('set_options', 'destination_id', res); + set_gsuite_template_options(frm, 'destination_id', res); } }); }, - set_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); - } }); +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); +}; From b7d4a3145a8dd2f759611f571e99278026ff7594 Mon Sep 17 00:00:00 2001 From: Raffael Meyer Date: Sun, 14 Apr 2019 00:17:34 +0200 Subject: [PATCH 020/299] make ID fields read only --- .../gsuite_templates/gsuite_templates.json | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.json b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.json index c3fc73b8c7..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,14 +78,17 @@ "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": "Select", "hidden": 0, @@ -87,7 +96,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 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,14 +145,17 @@ "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": "Select", "hidden": 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": "2019-03-26 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 From d3dac2f86eded564f3403f496383869bf356a1ef Mon Sep 17 00:00:00 2001 From: Raffael Meyer Date: Sun, 14 Apr 2019 00:20:59 +0200 Subject: [PATCH 021/299] rm unnecessary functions --- .../doctype/gsuite_templates/gsuite_templates.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js index 2721a9746f..ddaa740afd 100644 --- a/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js +++ b/frappe/integrations/doctype/gsuite_templates/gsuite_templates.js @@ -9,18 +9,6 @@ frappe.ui.form.on('GSuite Templates', { frm.trigger('set_available_folders'); } }, - template_id: function(frm) { - if (!frm.is_new()) { - // if doc is NOT new, get options when selecting field - frm.trigger('set_available_docs'); - } - }, - destination_id: function(frm) { - if (!frm.is_new()) { - // if doc is NOT new, get options when selecting field - frm.trigger('set_available_folders'); - } - }, set_available_docs: function(frm) { frappe.call({ // get documents from Google Drive From 8ab81eebb4715ab130080936025f9db7d2c1b590 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sun, 14 Apr 2019 11:09:03 +0530 Subject: [PATCH 022/299] fix: Cleanup modal after hide --- frappe/public/js/frappe/file_uploader/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frappe/public/js/frappe/file_uploader/index.js b/frappe/public/js/frappe/file_uploader/index.js index 9bac74f023..ac4ee865d9 100644 --- a/frappe/public/js/frappe/file_uploader/index.js +++ b/frappe/public/js/frappe/file_uploader/index.js @@ -66,5 +66,9 @@ export default class FileUploader { 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(); + }); } } From c99e7083806ae9dd31bb567b0fbc69ba548302f4 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sun, 14 Apr 2019 11:09:25 +0530 Subject: [PATCH 023/299] test: Wait for modal to hide --- cypress/integration/file_uploader.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cypress/integration/file_uploader.js b/cypress/integration/file_uploader.js index de2854261f..b58e0d49a8 100644 --- a/cypress/integration/file_uploader.js +++ b/cypress/integration/file_uploader.js @@ -29,6 +29,7 @@ context('FileUploader', () => { 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'); }); }); @@ -42,17 +43,19 @@ context('FileUploader', () => { 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({ force: true }); + 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'); }); }); From a3ee5ab6df9dffb3c8b38693a389acd7703f107a Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 15 Apr 2019 14:38:09 +0530 Subject: [PATCH 024/299] fix: save button should not remain disabled when the system is offline --- frappe/public/js/frappe/request.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/request.js b/frappe/public/js/frappe/request.js index cd102117d7..dd92e4109c 100644 --- a/frappe/public/js/frappe/request.js +++ b/frappe/public/js/frappe/request.js @@ -30,7 +30,8 @@ frappe.call = function(opts) { indicator: 'orange', message: __('You are not connected to Internet. Retry after sometime.') }, 3); - return; + opts.always && opts.always(); + return $.ajax(); } if (typeof arguments[0]==='string') { opts = { From 1a005337d8925bac659b2ceedfcb0199ff3f24c9 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Tue, 16 Apr 2019 09:29:29 +0530 Subject: [PATCH 025/299] fix: Do not rename or move files for custom doctype --- frappe/core/doctype/doctype/doctype.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index 484f12811c..62884aed81 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -343,7 +343,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): From 58e520a3f848c8568803ab4c08163b23d4b67491 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 16 Apr 2019 10:55:35 +0530 Subject: [PATCH 026/299] fix: Ignore permission while saving revert doc - Since on system manager can revert points --- frappe/public/js/frappe/misc/energy_point_utils.js | 3 ++- frappe/social/doctype/energy_point_log/energy_point_log.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/misc/energy_point_utils.js b/frappe/public/js/frappe/misc/energy_point_utils.js index dc7df166ec..f988560b27 100644 --- a/frappe/public/js/frappe/misc/energy_point_utils.js +++ b/frappe/public/js/frappe/misc/energy_point_utils.js @@ -32,6 +32,7 @@ Object.assign(frappe.energy_points, { get_history_log_message(log) { const doc_link = frappe.utils.get_form_link(log.reference_doctype, log.reference_name, true); const owner_name = frappe.user.full_name(log.owner).bold(); + const user = frappe.user.full_name(log.user).bold(); if (log.type === 'Appreciation') { return __('{0} appreciated on {1}', [owner_name, doc_link]); } @@ -39,7 +40,7 @@ Object.assign(frappe.energy_points, { return __('{0} criticized on {1}', [owner_name, doc_link]); } if (log.type === 'Revert') { - return __('{0} reverted {1}', [owner_name, + return __('{0} reverted {1}', [user, frappe.utils.get_form_link('Energy Point Log', log.revert_of, true)]); } return __('via automatic rule {0} on {1}', [log.rule.bold(), doc_link]); diff --git a/frappe/social/doctype/energy_point_log/energy_point_log.py b/frappe/social/doctype/energy_point_log/energy_point_log.py index 35aefcbb72..2076815e25 100644 --- a/frappe/social/doctype/energy_point_log/energy_point_log.py +++ b/frappe/social/doctype/energy_point_log/energy_point_log.py @@ -183,7 +183,7 @@ def revert(name, reason): frappe.throw(_('This document cannot be reverted')) doc_to_revert.reverted = 1 - doc_to_revert.save() + doc_to_revert.save(ignore_permissions=True) revert_log = frappe.get_doc({ 'doctype': 'Energy Point Log', @@ -194,7 +194,7 @@ def revert(name, reason): 'reference_doctype': doc_to_revert.reference_doctype, 'reference_name': doc_to_revert.reference_name, 'revert_of': doc_to_revert.name - }).insert() + }).insert(ignore_permissions=True) return revert_log From 4d884034015d8e8f32873d9f5cc8ac50f6836c9a Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 16 Apr 2019 12:08:24 +0530 Subject: [PATCH 027/299] fix: Disable submit button while doing network request - to avoid duplicate entries --- frappe/public/js/frappe/form/review.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frappe/public/js/frappe/form/review.js b/frappe/public/js/frappe/form/review.js index 8447118644..e3a90c4ab5 100644 --- a/frappe/public/js/frappe/form/review.js +++ b/frappe/public/js/frappe/form/review.js @@ -115,6 +115,7 @@ frappe.ui.form.Review = class Review { label: __('Reason') }], primary_action: (values) => { + review_dialog.disable_primary_action(); if (values.points > this.points.review_points) { return frappe.msgprint(__('You do not have enough points')); } @@ -133,6 +134,8 @@ frappe.ui.form.Review = class Review { this.frm.get_docinfo().energy_point_logs.unshift(review); this.frm.timeline.refresh(); this.update_reviewers(); + }).finally(() => { + review_dialog.enable_primary_action(); }); }, primary_action_label: __('Submit') From 64187bb451d57384100c5e8e206524e7b59bab21 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Tue, 16 Apr 2019 12:53:37 +0530 Subject: [PATCH 028/299] fix: Custom columns handling for prepared report --- frappe/core/doctype/prepared_report/prepared_report.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frappe/core/doctype/prepared_report/prepared_report.py b/frappe/core/doctype/prepared_report/prepared_report.py index 1cd106dabd..5217a6537d 100644 --- a/frappe/core/doctype/prepared_report/prepared_report.py +++ b/frappe/core/doctype/prepared_report/prepared_report.py @@ -37,6 +37,15 @@ class PreparedReport(Document): def run_background(instance): report = frappe.get_doc("Report", instance.ref_report_doctype) + + 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) From fc78e8eeed6138a6c0f379a8a28db16afa343692 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 16 Apr 2019 13:20:26 +0530 Subject: [PATCH 029/299] fix: Show help text for public/private toggle --- .../js/frappe/file_uploader/FilePreview.vue | 8 ------ .../js/frappe/file_uploader/FileUploader.vue | 28 +++++++++++-------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/frappe/public/js/frappe/file_uploader/FilePreview.vue b/frappe/public/js/frappe/file_uploader/FilePreview.vue index 6d3fac14c1..08c38d60f5 100644 --- a/frappe/public/js/frappe/file_uploader/FilePreview.vue +++ b/frappe/public/js/frappe/file_uploader/FilePreview.vue @@ -39,10 +39,6 @@
-
@@ -113,8 +109,4 @@ export default { display: flex; cursor: pointer; } - -.file-private { - position: absolute; -} diff --git a/frappe/public/js/frappe/file_uploader/FileUploader.vue b/frappe/public/js/frappe/file_uploader/FileUploader.vue index 2325f60cf4..6bc1f181ba 100644 --- a/frappe/public/js/frappe/file_uploader/FileUploader.vue +++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue @@ -62,18 +62,22 @@ @toggle_private="toggle_private(i)" />
- +
+ +
+ {{ __('Click on the lock icon to toggle public/private') }} +
+
Date: Tue, 16 Apr 2019 13:20:32 +0530 Subject: [PATCH 030/299] fix: Alignment --- frappe/public/js/frappe/form/footer/attachment.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/footer/attachment.html b/frappe/public/js/frappe/form/footer/attachment.html index 3598f8b9ef..c1fe3f3c85 100644 --- a/frappe/public/js/frappe/form/footer/attachment.html +++ b/frappe/public/js/frappe/form/footer/attachment.html @@ -1,4 +1,4 @@ -
  • +
  • × From 3489ae44d2693b85bb51364fe8d640bda1472b9a Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 16 Apr 2019 13:32:09 +0530 Subject: [PATCH 031/299] fix: Show Hidden fields in Report Builder --- frappe/public/js/frappe/views/reports/report_view.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js index 98f198b5cf..d0cdeac79a 100644 --- a/frappe/public/js/frappe/views/reports/report_view.js +++ b/frappe/public/js/frappe/views/reports/report_view.js @@ -741,9 +741,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { let out = {}; const standard_fields_filter = df => - !in_list(frappe.model.no_value_type, df.fieldtype) && - !df.report_hide && df.fieldname !== 'naming_series' && - !df.hidden; + !in_list(frappe.model.no_value_type, df.fieldtype) && !df.report_hide; let doctype_fields = frappe.meta.get_docfields(this.doctype).filter(standard_fields_filter); From 012137d0ebe591885d13ec4be8628473a51c8517 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 16 Apr 2019 13:47:35 +0530 Subject: [PATCH 032/299] fix: Allow numeric filter without using = --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f0ae54aa59..26f83ee06c 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "cookie": "^0.3.1", "express": "^4.16.2", "fast-deep-equal": "^2.0.1", - "frappe-datatable": "^1.12.0", + "frappe-datatable": "^1.12.1", "frappe-gantt": "^0.1.0", "fuse.js": "^3.2.0", "highlight.js": "^9.12.0", diff --git a/yarn.lock b/yarn.lock index 98cd290a82..88c2be16e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1722,10 +1722,10 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -frappe-datatable@^1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/frappe-datatable/-/frappe-datatable-1.12.0.tgz#2273535ead4404e5b165b6564c622acbacfdf61e" - integrity sha512-rrsRaxP9+CwPdJiYzmgmYD5ud+0pWzon8n+DKBrnrbFheN5SFnbuRdR58G8qA4/psHIN3rrSEximiQsbTUNdzw== +frappe-datatable@^1.12.1: + version "1.12.1" + resolved "https://registry.yarnpkg.com/frappe-datatable/-/frappe-datatable-1.12.1.tgz#6efe342346025ffeed822e188a05da6c9c9230c9" + integrity sha512-AC2sJDuJOr0nSfT+w7DPZd7zPW7PHGhg9XxdRNlaAYpy45r3owdJVF+R6lCMQRvFvvzmPMht02EOE6cFpkzLKw== dependencies: hyperlist "^1.0.0-beta" lodash "^4.17.5" From 70c256f81b9b13e702a34686177352effca04cb9 Mon Sep 17 00:00:00 2001 From: karthikeyan5 Date: Mon, 18 Mar 2019 18:40:55 +0530 Subject: [PATCH 033/299] feat(Raw Printing): Adding Support for qz-tray --- .../doctype/print_format/print_format.json | 1590 +++++++++-------- frappe/public/build.json | 4 +- frappe/public/js/frappe/form/print.js | 237 ++- .../frappe/form/templates/print_layout.html | 4 +- frappe/www/printview.py | 40 +- package.json | 2 + yarn.lock | 10 + 7 files changed, 1139 insertions(+), 748 deletions(-) diff --git a/frappe/printing/doctype/print_format/print_format.json b/frappe/printing/doctype/print_format/print_format.json index f8c8f97105..1d96d9f0c7 100644 --- a/frappe/printing/doctype/print_format/print_format.json +++ b/frappe/printing/doctype/print_format/print_format.json @@ -1,767 +1,881 @@ { - "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": "", + "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, + "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, + "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, + "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", + "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\n

    Notes:

    \n\n
      \n
    1. All field groups (label + value) are set attributes data-fieldtype and data-fieldname
    2. \n
    3. All values are given class value
    4. \n
    5. All Section Breaks are given class section-break
    6. \n
    7. All Column Breaks are given class column-break
    8. \n
    \n\n

    Examples

    \n\n

    1. Left align integers

    \n\n
    [data-fieldtype=\"Int\"] .value { text-left: left; }
    \n\n

    1. 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, + "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", + "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
    \n

    Introduction

    \n

    Print 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.

    \n

    For styling, the Boostrap CSS framework is provided and you can enjoy the full range of classes.

    \n
    \n

    References

    \n
      \n\t
    1. Jinja Tempalting Language: Reference
    2. \n\t
    3. Bootstrap CSS Framework
    4. \n
    \n
    \n

    Example

    \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
    \n

    Common Functions

    \n\n\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\n
    doc.get_formatted(\"[fieldname]\", [parent_doc])Get document value formatted as Date, Currency etc. Pass parent doc for curreny type fields.
    frappe.db.get_value(\"[doctype]\", \"[name]\", \"fieldname\")Get value from another document.
    \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": "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, + "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": "", + "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", + "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", + "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", + "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", + "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", + "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", + "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, + "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, + "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", + "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", + "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, + "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, + "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\n

    Notes:

    \n\n
      \n
    1. All field groups (label + value) are set attributes data-fieldtype and data-fieldname
    2. \n
    3. All values are given class value
    4. \n
    5. All Section Breaks are given class section-break
    6. \n
    7. All Column Breaks are given class column-break
    8. \n
    \n\n

    Examples

    \n\n

    1. Left align integers

    \n\n
    [data-fieldtype=\"Int\"] .value { text-left: left; }
    \n\n

    1. 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", + "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", + "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
    \n

    Introduction

    \n

    Print 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.

    \n

    For styling, the Boostrap CSS framework is provided and you can enjoy the full range of classes.

    \n
    \n

    References

    \n
      \n\t
    1. Jinja Tempalting Language: Reference
    2. \n\t
    3. Bootstrap CSS Framework
    4. \n
    \n
    \n

    Example

    \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
    \n

    Common Functions

    \n\n\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\n
    doc.get_formatted(\"[fieldname]\", [parent_doc])Get document value formatted as Date, Currency etc. Pass parent doc for curreny type fields.
    frappe.db.get_value(\"[doctype]\", \"[name]\", \"fieldname\")Get value from another document.
    \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, + "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, + "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_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": "2019-03-01 12:25:31.874685", + "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, + "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 +} \ No newline at end of file diff --git a/frappe/public/build.json b/frappe/public/build.json index 620b360f47..bc4db001ac 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -153,7 +153,9 @@ "public/js/lib/leaflet/leaflet.js", "public/js/lib/leaflet/leaflet.draw.js", "public/js/lib/leaflet/L.Control.Locate.js", - "public/js/lib/leaflet/easy-button.js" + "public/js/lib/leaflet/easy-button.js", + "node_modules/js-sha256/build/sha256.min.js", + "node_modules/qz-tray/qz-tray.js" ], "js/desk.min.js": [ "public/js/frappe/class.js", diff --git a/frappe/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index f0a4226444..21591c2b43 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -1,5 +1,9 @@ frappe.provide("frappe.ui.form"); +// init qz tray library +qz.api.setPromiseType(function promise(resolver) { return new Promise(resolver); }); +qz.api.setSha256Type(function(data) { return sha256(data); }); + frappe.ui.form.PrintPreview = Class.extend({ init: function (opts) { $.extend(this, opts); @@ -47,6 +51,10 @@ frappe.ui.form.PrintPreview = Class.extend({ me.multilingual_preview() }); + this.wrapper.find(".btn-qz-settings").click(function () { + me.qz_setting_dialog() + }); + this.wrapper.find(".btn-print-print").click(function () { if (me.is_old_style()) { me.print_old_style(); @@ -125,10 +133,18 @@ frappe.ui.form.PrintPreview = Class.extend({ multilingual_preview: function () { var me = this; if (this.is_old_style()) { + me.wrapper.find(".btn-print-preview").toggle(true); me.wrapper.find(".btn-download-pdf").toggle(false); me.set_style(); - me.preview_old_style(); - } else { + me.preview_old_style(); + } + else if (this.is_raw_printing()){ + me.wrapper.find(".btn-print-preview").toggle(false); + me.wrapper.find(".btn-download-pdf").toggle(false); + me.preview(); + } + else { + me.wrapper.find(".btn-print-preview").toggle(true); me.wrapper.find(".btn-download-pdf").toggle(true); me.preview(); } @@ -190,7 +206,47 @@ frappe.ui.form.PrintPreview = Class.extend({ callback: function (data) { } }); - } else { + } + else if(me.get_mapped_printer().length == 1){ + // printer is already mapped in localstorage (applies for both raw and pdf ) + if(me.is_raw_printing()){ + me.get_raw_commands(function(out) { + let printer_map = me.get_mapped_printer()[0] + let config = qz.configs.create(printer_map.printer) + let data = [out.raw_commands] + frappe.ui.form.qz_connect().then(function(){ + return qz.print(config,data); + }).then(frappe.ui.form.qz_success).catch((err)=>{ + frappe.ui.form.qz_fail(err); + }) + }) + } + else{ + frappe.show_alert({message:__('PDF Printing via QZ is not yet supported. Please remove QZ printer mapping for this Print format and try again.'),indicator:'blue'},14) + //Note: need to solve "Error: Cannot parse (FILE) as a PDF file" to enable qz pdf printing. + + // // use pdf method print method of qz + // let printer_map = me.get_mapped_printer()[0] + // let config = qz.configs.create(printer_map.printer) + // let pdf_url = frappe.urllib.get_full_url("/api/method/frappe.utils.print_format.download_pdf?" + // + "doctype=" + encodeURIComponent(me.frm.doc.doctype) + // + "&name=" + encodeURIComponent(me.frm.doc.name) + // + "&format=" + me.selected_format() + // + "&no_letterhead=" + (me.with_letterhead() ? "0" : "1") + // + (me.lang_code ? ("&_lang=" + me.lang_code) : "")) + // let data = [{type: 'pdf', data: pdf_url}] + // frappe.ui.form.qz_connect().then(function(){ + // return qz.print(config,data); + // }).then(frappe.ui.form.qz_success).catch((err)=>{ + // frappe.ui.form.qz_fail(err); + // }) + } + } + else if(me.is_raw_printing()) { + frappe.show_alert({message:__('Please set a printer mapping for this print format in the QZ Settings'),indicator:'blue'},14) + me.qz_setting_dialog() + } + else { me.new_page_preview(true); } } @@ -225,6 +281,31 @@ frappe.ui.form.PrintPreview = Class.extend({ } }); }, + get_raw_commands: function (callback) { + frappe.call({ + method: "frappe.www.printview.get_rendered_raw_commands", + args: { + doc: this.frm.doc, + print_format: this.selected_format(), + _lang: this.lang_code + }, + callback: function (r) { + if (!r.exc) { + callback(r.message); + } + } + }); + }, + get_mapped_printer: function() { + if(localStorage && localStorage.print_format_printer_map + && JSON.parse(localStorage.print_format_printer_map)[this.frm.doctype]) { + return (JSON.parse(localStorage.print_format_printer_map)[this.frm.doctype]) + .filter((printer_map)=> printer_map.print_format == this.selected_format()) + } + else { + return [] + } + }, preview_old_style: function () { var me = this; this.with_old_style({ @@ -270,6 +351,9 @@ frappe.ui.form.PrintPreview = Class.extend({ is_old_style: function (format) { return this.get_print_format(format).print_format_type === "Client"; }, + is_raw_printing: function (format) { + return this.get_print_format(format).raw_printing == true; + }, get_print_format: function (format) { if (!format) { format = this.selected_format(); @@ -286,6 +370,76 @@ frappe.ui.form.PrintPreview = Class.extend({ }, set_style: function (style) { frappe.dom.set_style(style || frappe.boot.print_css, "print-style"); + }, + qz_setting_dialog: function() { + var me = this + if (localStorage && localStorage.print_format_printer_map) + this.print_format_printer_map = JSON.parse(localStorage.print_format_printer_map); + else + this.print_format_printer_map = {} + this.data = []; + this.data = this.print_format_printer_map[this.frm.doctype] || [] + this.printer_list = []; + frappe.ui.form.qz_get_printer_list().then((data)=>{ + this.printer_list = data; + if (!(this.printer_list && this.printer_list.length)) { + frappe.throw(__("No Printer is Available.")); + } + const dialog = new frappe.ui.Dialog({ + title: __("QZ Tray Print Settings"), + fields: [ + {fieldtype:'Section Break', label: __('Printer Mapping')}, + { + fieldname: "printer_mapping", + fieldtype: "Table", + in_place_edit: true, + data: this.data, + get_data: () => { + return this.data; + }, + fields: [{ + fieldtype:'Select', + fieldname:"print_format", + default: 0, + options: this.print_formats, + read_only: 0, + in_list_view: 1, + label: __('Print Format') + }, { + fieldtype:'Select', + fieldname:"printer", + default: 0, + options: this.printer_list, + read_only: 0, + in_list_view: 1, + label: __('Printer') + }] + }, + ], + primary_action: function() { + let printer_mapping = this.get_values()["printer_mapping"]; + if (printer_mapping && printer_mapping.length) { + let print_format_list = printer_mapping.map(a => a.print_format); + let has_duplicate = print_format_list.some((item, idx) => print_format_list.indexOf(item) != idx ) + if (has_duplicate) + frappe.throw(__("Cannot have multiple printers mapped to a single print format.")); + } + else { + printer_mapping = [] + } + if (localStorage && localStorage.print_format_printer_map) + this.print_format_printer_map = JSON.parse(localStorage.print_format_printer_map); + else + this.print_format_printer_map = {} + this.print_format_printer_map[me.frm.doctype] = printer_mapping; + localStorage.print_format_printer_map = JSON.stringify(this.print_format_printer_map) + this.hide(); + }, + primary_action_label: __('Save') + }); + dialog.show(); + }); + } }); @@ -326,3 +480,80 @@ frappe.ui.get_print_settings = function (pdf, callback, letter_head) { callback(data); }, __("Print Settings")); } + + +// qz connection wrapper +// - allows active and inactive connections to resolve regardless +// - try to connect once before firing the mimetype launcher +// - if connection fails, catch the reject, fire the mimetype launcher +// - after mimetype launcher is fired, try to connect 3 more times +// - display success/fail meaasges to user +frappe.ui.form.qz_connect = function() { + return new Promise(function(resolve, reject) { + if (qz.websocket.isActive()) { // if already active, resolve immediately + // frappe.show_alert({message: __('QZ Tray Connection Active!'), indicator: 'green'}); + resolve(); + } else { + // try to connect once before firing the mimetype launcher + frappe.show_alert({message: __('Attemting Connection to QZ Tray!'), indicator: 'blue'}); + qz.websocket.connect().then(()=>{ + frappe.show_alert({message: __('Connected to QZ Tray!'), indicator: 'green'}); + resolve(); + }, function retry(err) { + if (err.message === 'Unable to establish connection with QZ'){ + // if a connect was not succesful, launch the mimetime, try 3 more times + frappe.show_alert({message: __('Attemting to launch QZ Tray!'), indicator: 'blue'},14); + window.location.assign("qz:launch"); + qz.websocket.connect({ retries: 3, delay: 1 }).then(()=>{ + frappe.show_alert({message: __('Connected to QZ Tray!'), indicator: 'green'}); + resolve(); + }, (err)=>{ + frappe.show_alert({message: __('Error connecting to QZ Tray! Click here to Download QZ Tray'), indicator: 'red'},14); + reject(); + }); + } + else{ + frappe.show_alert({message: 'QZ Tray '+err.toString(), indicator: 'red'},14); + reject(); + } + }); + } + }); +} + +frappe.ui.form.qz_get_printer_list = function(){ + return frappe.ui.form.qz_connect().then(function(){ + return qz.printers.find() + }).then((data)=>{ + return data + }).catch((err)=>{ + frappe.ui.form.qz_fail(err); + }) +} + +// notify qz successful print +frappe.ui.form.qz_success = function() { + frappe.show_alert({message: __('QZ print complete!'), indicator: 'green'}); +} + +// notify qz errors +frappe.ui.form.qz_fail = function(e) { + console.error("qz error:",e) + frappe.show_alert({message:__("QZ Tray Failed") + e.toString(), indicator:'red'},20); +} + + +// flow for action after print button is clicked +// - if printer is already mapped in localstorage (applies for both raw and pdf ) +// - qz_connect() +// - search for configured printer and create config +// - if the above fails throw error with printer not found. (and instructions/options to remove all mapping from localstorage for this printer) +// - if raw_printing call appropriate qz fn +// - else call pdf and then call appropriate qz fn with that pdf +// - else if raw_printing == true +// - qz_connect() +// - if search returns printers +// - show modal with list of printer and ask to map +// - store in LocalStorage +// - else throw error that no printer is available + diff --git a/frappe/public/js/frappe/form/templates/print_layout.html b/frappe/public/js/frappe/form/templates/print_layout.html index b2abd11099..2457a1ff58 100644 --- a/frappe/public/js/frappe/form/templates/print_layout.html +++ b/frappe/public/js/frappe/form/templates/print_layout.html @@ -18,7 +18,9 @@ {%= __("Print") %} - {%= __("Settings...") %} + {%= __("Settings...") %} + + {%= __("QZ Settings...") %} {%= __("Customize...") %} diff --git a/frappe/www/printview.py b/frappe/www/printview.py index 070092112f..d90cb4a26e 100644 --- a/frappe/www/printview.py +++ b/frappe/www/printview.py @@ -34,7 +34,7 @@ def get_context(context): print_format = get_print_format_doc(None, meta = meta) return { - "body": get_html(doc, print_format = print_format, + "body": get_rendered_template(doc, print_format = print_format, meta=meta, trigger_print = frappe.form_dict.trigger_print, no_letterhead=frappe.form_dict.no_letterhead), "css": get_print_style(frappe.form_dict.style, print_format), @@ -58,7 +58,7 @@ def get_print_format_doc(print_format_name, meta): # if old name, return standard! return None -def get_html(doc, name=None, print_format=None, meta=None, +def get_rendered_template(doc, name=None, print_format=None, meta=None, no_letterhead=None, trigger_print=False): print_settings = frappe.db.get_singles_dict("Print Settings") @@ -179,14 +179,42 @@ def get_html_and_style(doc, name=None, print_format=None, meta=None, if isinstance(doc, string_types): doc = frappe.get_doc(json.loads(doc)) - + print_format = get_print_format_doc(print_format, meta=meta or frappe.get_meta(doc.doctype)) + + if print_format and print_format.raw_printing: + return { + "html": '
    ' + + _("Note: This Print Format is in Raw Commands and cannot be previewed.") + + '
    ' + } + return { - "html": get_html(doc, name=name, print_format=print_format, meta=meta, + "html": get_rendered_template(doc, name=name, print_format=print_format, meta=meta, no_letterhead=no_letterhead, trigger_print=trigger_print), "style": get_print_style(style=style, print_format=print_format) } +@frappe.whitelist() +def get_rendered_raw_commands(doc, name=None, print_format=None, meta=None, lang=None): + """Returns Rendered Raw Commands of print format, used to send directly to printer""" + + if isinstance(doc, string_types) and isinstance(name, string_types): + doc = frappe.get_doc(doc, name) + + if isinstance(doc, string_types): + doc = frappe.get_doc(json.loads(doc)) + + print_format = get_print_format_doc(print_format, meta=meta or frappe.get_meta(doc.doctype)) + + if not print_format or (print_format and not print_format.raw_printing): + frappe.throw(_("{0} is not a raw printing format.").format(print_format), + frappe.TemplateNotFoundError) + + return { + "raw_commands": get_rendered_template(doc, name=name, print_format=print_format, meta=meta) + } + def validate_print_permission(doc): if frappe.form_dict.get("key"): if frappe.form_dict.key == doc.get_signature(): @@ -218,8 +246,10 @@ def get_print_format(doctype, print_format): with open(path, "r") as pffile: return pffile.read() else: - if print_format.html: + if print_format.html and not print_format.raw_printing: return print_format.html + elif print_format.raw_commands and print_format.raw_printing: + return print_format.raw_commands else: frappe.throw(_("No template found at path: {0}").format(path), frappe.TemplateNotFoundError) diff --git a/package.json b/package.json index f0ae54aa59..0e5f09a1ab 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,12 @@ "frappe-gantt": "^0.1.0", "fuse.js": "^3.2.0", "highlight.js": "^9.12.0", + "js-sha256": "^0.9.0", "jsbarcode": "^3.9.0", "moment": "^2.20.1", "moment-timezone": "^0.5.21", "quill": "2.0.0-dev.2", + "qz-tray": "^2.0.8", "redis": "^2.8.0", "showdown": "^1.8.6", "socket.io": "^2.0.4", diff --git a/yarn.lock b/yarn.lock index 98cd290a82..43da768e06 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2452,6 +2452,11 @@ js-base64@^2.1.8, js-base64@^2.1.9: resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121" integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw== +js-sha256@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" + integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== + js-yaml@^3.12.0, js-yaml@^3.9.0: version "3.12.2" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.2.tgz#ef1d067c5a9d9cb65bd72f285b5d8105c77f14fc" @@ -3852,6 +3857,11 @@ quill@2.0.0-dev.2: parchment quilljs/parchment#487850f7eb030a6c4e750ba809e58b09444e0bdb quill-delta "^3.6.2" +qz-tray@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/qz-tray/-/qz-tray-2.0.8.tgz#5e15d102cf3a11a31ddb332891c7f8a6af8f6ad5" + integrity sha512-lncGYzz7/sTORZuC1S3ukNlMPCMOmsHWNvJF4FjMCZ2+0UV3txi6kgPd754B7kDFKm0J587sIODgxIlFY7qU4w== + ramda@0.24.1: version "0.24.1" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857" From 043c41357195fc791a65d144b9034028e99a968d Mon Sep 17 00:00:00 2001 From: karthikeyan5 Date: Mon, 18 Mar 2019 20:01:52 +0530 Subject: [PATCH 034/299] fix(Raw Printing): fixing code standard --- .eslintrc | 3 +- frappe/public/js/frappe/form/print.js | 69 +++++++++++++++------------ frappe/www/printview.py | 4 +- 3 files changed, 42 insertions(+), 34 deletions(-) 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/frappe/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index 21591c2b43..02695847e1 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -1,8 +1,12 @@ frappe.provide("frappe.ui.form"); // init qz tray library -qz.api.setPromiseType(function promise(resolver) { return new Promise(resolver); }); -qz.api.setSha256Type(function(data) { return sha256(data); }); +qz.api.setPromiseType(function promise(resolver) { + return new Promise(resolver); +}); +qz.api.setSha256Type(function(data) { + return sha256(data); +}); frappe.ui.form.PrintPreview = Class.extend({ init: function (opts) { @@ -207,13 +211,13 @@ frappe.ui.form.PrintPreview = Class.extend({ } }); } - else if(me.get_mapped_printer().length == 1){ + else if(me.get_mapped_printer().length === 1){ // printer is already mapped in localstorage (applies for both raw and pdf ) if(me.is_raw_printing()){ me.get_raw_commands(function(out) { - let printer_map = me.get_mapped_printer()[0] - let config = qz.configs.create(printer_map.printer) - let data = [out.raw_commands] + let printer_map = me.get_mapped_printer()[0]; + let config = qz.configs.create(printer_map.printer); + let data = [out.raw_commands]; frappe.ui.form.qz_connect().then(function(){ return qz.print(config,data); }).then(frappe.ui.form.qz_success).catch((err)=>{ @@ -222,7 +226,7 @@ frappe.ui.form.PrintPreview = Class.extend({ }) } else{ - frappe.show_alert({message:__('PDF Printing via QZ is not yet supported. Please remove QZ printer mapping for this Print format and try again.'),indicator:'blue'},14) + frappe.show_alert({message:__('PDF Printing via QZ is not yet supported. Please remove QZ printer mapping for this Print format and try again.'),indicator:'blue'},14); //Note: need to solve "Error: Cannot parse (FILE) as a PDF file" to enable qz pdf printing. // // use pdf method print method of qz @@ -243,8 +247,8 @@ frappe.ui.form.PrintPreview = Class.extend({ } } else if(me.is_raw_printing()) { - frappe.show_alert({message:__('Please set a printer mapping for this print format in the QZ Settings'),indicator:'blue'},14) - me.qz_setting_dialog() + frappe.show_alert({message:__('Please set a printer mapping for this print format in the QZ Settings'),indicator:'blue'},14); + me.qz_setting_dialog(); } else { me.new_page_preview(true); @@ -300,10 +304,10 @@ frappe.ui.form.PrintPreview = Class.extend({ if(localStorage && localStorage.print_format_printer_map && JSON.parse(localStorage.print_format_printer_map)[this.frm.doctype]) { return (JSON.parse(localStorage.print_format_printer_map)[this.frm.doctype]) - .filter((printer_map)=> printer_map.print_format == this.selected_format()) + .filter((printer_map)=> printer_map.print_format == this.selected_format()); } else { - return [] + return []; } }, preview_old_style: function () { @@ -352,7 +356,7 @@ frappe.ui.form.PrintPreview = Class.extend({ return this.get_print_format(format).print_format_type === "Client"; }, is_raw_printing: function (format) { - return this.get_print_format(format).raw_printing == true; + return this.get_print_format(format).raw_printing === true; }, get_print_format: function (format) { if (!format) { @@ -372,13 +376,13 @@ frappe.ui.form.PrintPreview = Class.extend({ frappe.dom.set_style(style || frappe.boot.print_css, "print-style"); }, qz_setting_dialog: function() { - var me = this + var me = this; if (localStorage && localStorage.print_format_printer_map) this.print_format_printer_map = JSON.parse(localStorage.print_format_printer_map); else - this.print_format_printer_map = {} + this.print_format_printer_map = {}; this.data = []; - this.data = this.print_format_printer_map[this.frm.doctype] || [] + this.data = this.print_format_printer_map[this.frm.doctype] || []; this.printer_list = []; frappe.ui.form.qz_get_printer_list().then((data)=>{ this.printer_list = data; @@ -388,10 +392,11 @@ frappe.ui.form.PrintPreview = Class.extend({ const dialog = new frappe.ui.Dialog({ title: __("QZ Tray Print Settings"), fields: [ - {fieldtype:'Section Break', label: __('Printer Mapping')}, + {fieldtype:'Section Break'}, { fieldname: "printer_mapping", fieldtype: "Table", + label: __('Printer Mapping'), in_place_edit: true, data: this.data, get_data: () => { @@ -420,19 +425,19 @@ frappe.ui.form.PrintPreview = Class.extend({ let printer_mapping = this.get_values()["printer_mapping"]; if (printer_mapping && printer_mapping.length) { let print_format_list = printer_mapping.map(a => a.print_format); - let has_duplicate = print_format_list.some((item, idx) => print_format_list.indexOf(item) != idx ) + let has_duplicate = print_format_list.some((item, idx) => print_format_list.indexOf(item) != idx ); if (has_duplicate) frappe.throw(__("Cannot have multiple printers mapped to a single print format.")); } else { - printer_mapping = [] + printer_mapping = []; } if (localStorage && localStorage.print_format_printer_map) this.print_format_printer_map = JSON.parse(localStorage.print_format_printer_map); else - this.print_format_printer_map = {} + this.print_format_printer_map = {}; this.print_format_printer_map[me.frm.doctype] = printer_mapping; - localStorage.print_format_printer_map = JSON.stringify(this.print_format_printer_map) + localStorage.print_format_printer_map = JSON.stringify(this.print_format_printer_map); this.hide(); }, primary_action_label: __('Save') @@ -489,14 +494,15 @@ frappe.ui.get_print_settings = function (pdf, callback, letter_head) { // - after mimetype launcher is fired, try to connect 3 more times // - display success/fail meaasges to user frappe.ui.form.qz_connect = function() { - return new Promise(function(resolve, reject) { + return new Promise(function(resolve, reject) { if (qz.websocket.isActive()) { // if already active, resolve immediately // frappe.show_alert({message: __('QZ Tray Connection Active!'), indicator: 'green'}); resolve(); - } else { + } + else { // try to connect once before firing the mimetype launcher frappe.show_alert({message: __('Attemting Connection to QZ Tray!'), indicator: 'blue'}); - qz.websocket.connect().then(()=>{ + qz.websocket.connect().then(()=>{ frappe.show_alert({message: __('Connected to QZ Tray!'), indicator: 'green'}); resolve(); }, function retry(err) { @@ -504,13 +510,14 @@ frappe.ui.form.qz_connect = function() { // if a connect was not succesful, launch the mimetime, try 3 more times frappe.show_alert({message: __('Attemting to launch QZ Tray!'), indicator: 'blue'},14); window.location.assign("qz:launch"); - qz.websocket.connect({ retries: 3, delay: 1 }).then(()=>{ - frappe.show_alert({message: __('Connected to QZ Tray!'), indicator: 'green'}); - resolve(); - }, (err)=>{ - frappe.show_alert({message: __('Error connecting to QZ Tray!
    Click here to Download QZ Tray'), indicator: 'red'},14); - reject(); - }); + qz.websocket.connect({ retries: 3, delay: 1 }).then(()=>{ + frappe.show_alert({message: __('Connected to QZ Tray!'), indicator: 'green'}); + resolve(); + }, (err)=>{ + frappe.show_alert({message: __('Error connecting to QZ Tray! Click here to Download QZ Tray'), indicator: 'red'},14); + console.error("qz error:",err) + reject(); + }); } else{ frappe.show_alert({message: 'QZ Tray '+err.toString(), indicator: 'red'},14); @@ -528,7 +535,7 @@ frappe.ui.form.qz_get_printer_list = function(){ return data }).catch((err)=>{ frappe.ui.form.qz_fail(err); - }) + }); } // notify qz successful print diff --git a/frappe/www/printview.py b/frappe/www/printview.py index d90cb4a26e..c05afc294c 100644 --- a/frappe/www/printview.py +++ b/frappe/www/printview.py @@ -186,7 +186,7 @@ def get_html_and_style(doc, name=None, print_format=None, meta=None, return { "html": '
    ' + _("Note: This Print Format is in Raw Commands and cannot be previewed.") - + '
    ' + + '
  • ' } return { @@ -204,7 +204,7 @@ def get_rendered_raw_commands(doc, name=None, print_format=None, meta=None, lang if isinstance(doc, string_types): doc = frappe.get_doc(json.loads(doc)) - + print_format = get_print_format_doc(print_format, meta=meta or frappe.get_meta(doc.doctype)) if not print_format or (print_format and not print_format.raw_printing): From 92b8d82f941f4d6bfbac4d6ead5b27d1fbd1452e Mon Sep 17 00:00:00 2001 From: karthikeyan5 Date: Tue, 19 Mar 2019 16:23:56 +0530 Subject: [PATCH 035/299] fix(raw printing): codacy issues --- .eslintrc | 3 ++- frappe/public/js/frappe/form/print.js | 37 +++++++++++++-------------- frappe/www/printview.py | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.eslintrc b/.eslintrc index 3711a7dbe6..602476f153 100644 --- a/.eslintrc +++ b/.eslintrc @@ -141,6 +141,7 @@ "context": true, "before": true, "beforeEach": true, - "qz": true + "qz": true, + "sha256": true } } diff --git a/frappe/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index 02695847e1..0cacf4fdeb 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -56,7 +56,7 @@ frappe.ui.form.PrintPreview = Class.extend({ }); this.wrapper.find(".btn-qz-settings").click(function () { - me.qz_setting_dialog() + me.qz_setting_dialog(); }); this.wrapper.find(".btn-print-print").click(function () { @@ -222,10 +222,10 @@ frappe.ui.form.PrintPreview = Class.extend({ return qz.print(config,data); }).then(frappe.ui.form.qz_success).catch((err)=>{ frappe.ui.form.qz_fail(err); - }) - }) + }); + }); } - else{ + else { frappe.show_alert({message:__('PDF Printing via QZ is not yet supported. Please remove QZ printer mapping for this Print format and try again.'),indicator:'blue'},14); //Note: need to solve "Error: Cannot parse (FILE) as a PDF file" to enable qz pdf printing. @@ -506,33 +506,33 @@ frappe.ui.form.qz_connect = function() { frappe.show_alert({message: __('Connected to QZ Tray!'), indicator: 'green'}); resolve(); }, function retry(err) { - if (err.message === 'Unable to establish connection with QZ'){ + if (err.message === 'Unable to establish connection with QZ') { // if a connect was not succesful, launch the mimetime, try 3 more times frappe.show_alert({message: __('Attemting to launch QZ Tray!'), indicator: 'blue'},14); window.location.assign("qz:launch"); qz.websocket.connect({ retries: 3, delay: 1 }).then(()=>{ frappe.show_alert({message: __('Connected to QZ Tray!'), indicator: 'green'}); resolve(); - }, (err)=>{ + }, + ()=> { frappe.show_alert({message: __('Error connecting to QZ Tray! Click here to Download QZ Tray'), indicator: 'red'},14); - console.error("qz error:",err) reject(); }); - } - else{ - frappe.show_alert({message: 'QZ Tray '+err.toString(), indicator: 'red'},14); - reject(); - } + } + else { + frappe.show_alert({message: 'QZ Tray '+err.toString(), indicator: 'red'},14); + reject(); + } }); - } - }); + } + }); } frappe.ui.form.qz_get_printer_list = function(){ return frappe.ui.form.qz_connect().then(function(){ - return qz.printers.find() + return qz.printers.find(); }).then((data)=>{ - return data + return data; }).catch((err)=>{ frappe.ui.form.qz_fail(err); }); @@ -540,13 +540,12 @@ frappe.ui.form.qz_get_printer_list = function(){ // notify qz successful print frappe.ui.form.qz_success = function() { - frappe.show_alert({message: __('QZ print complete!'), indicator: 'green'}); + frappe.show_alert({message: __('QZ print complete!'), indicator: 'green'}); } // notify qz errors frappe.ui.form.qz_fail = function(e) { - console.error("qz error:",e) - frappe.show_alert({message:__("QZ Tray Failed") + e.toString(), indicator:'red'},20); + frappe.show_alert({message:__("QZ Tray Failed") + e.toString(), indicator:'red'},20); } diff --git a/frappe/www/printview.py b/frappe/www/printview.py index c05afc294c..b7b147f83b 100644 --- a/frappe/www/printview.py +++ b/frappe/www/printview.py @@ -179,7 +179,7 @@ def get_html_and_style(doc, name=None, print_format=None, meta=None, if isinstance(doc, string_types): doc = frappe.get_doc(json.loads(doc)) - + print_format = get_print_format_doc(print_format, meta=meta or frappe.get_meta(doc.doctype)) if print_format and print_format.raw_printing: From d569059fa0af6273836b1c92c2f77d9f8027a8d2 Mon Sep 17 00:00:00 2001 From: karthikeyan5 Date: Wed, 20 Mar 2019 00:22:44 +0530 Subject: [PATCH 036/299] fix(raw printing): more codacy fixes --- frappe/public/js/frappe/form/print.js | 166 +++++++++++++++----------- 1 file changed, 94 insertions(+), 72 deletions(-) diff --git a/frappe/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index 0cacf4fdeb..fa15c07ebe 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -2,10 +2,10 @@ frappe.provide("frappe.ui.form"); // init qz tray library qz.api.setPromiseType(function promise(resolver) { - return new Promise(resolver); + return new Promise(resolver); }); -qz.api.setSha256Type(function(data) { - return sha256(data); +qz.api.setSha256Type(function (data) { + return sha256(data); }); frappe.ui.form.PrintPreview = Class.extend({ @@ -140,14 +140,12 @@ frappe.ui.form.PrintPreview = Class.extend({ me.wrapper.find(".btn-print-preview").toggle(true); me.wrapper.find(".btn-download-pdf").toggle(false); me.set_style(); - me.preview_old_style(); - } - else if (this.is_raw_printing()){ + me.preview_old_style(); + } else if (this.is_raw_printing()) { me.wrapper.find(".btn-print-preview").toggle(false); me.wrapper.find(".btn-download-pdf").toggle(false); me.preview(); - } - else { + } else { me.wrapper.find(".btn-print-preview").toggle(true); me.wrapper.find(".btn-download-pdf").toggle(true); me.preview(); @@ -210,23 +208,24 @@ frappe.ui.form.PrintPreview = Class.extend({ callback: function (data) { } }); - } - else if(me.get_mapped_printer().length === 1){ + } else if (me.get_mapped_printer().length === 1) { // printer is already mapped in localstorage (applies for both raw and pdf ) - if(me.is_raw_printing()){ - me.get_raw_commands(function(out) { + if (me.is_raw_printing()) { + me.get_raw_commands(function (out) { let printer_map = me.get_mapped_printer()[0]; let config = qz.configs.create(printer_map.printer); let data = [out.raw_commands]; - frappe.ui.form.qz_connect().then(function(){ - return qz.print(config,data); - }).then(frappe.ui.form.qz_success).catch((err)=>{ + frappe.ui.form.qz_connect().then(function () { + return qz.print(config, data); + }).then(frappe.ui.form.qz_success).catch((err) => { frappe.ui.form.qz_fail(err); }); }); - } - else { - frappe.show_alert({message:__('PDF Printing via QZ is not yet supported. Please remove QZ printer mapping for this Print format and try again.'),indicator:'blue'},14); + } else { + frappe.show_alert({ + message: __('PDF Printing via QZ is not yet supported. Please remove QZ printer mapping for this Print format and try again.'), + indicator: 'blue' + }, 14); //Note: need to solve "Error: Cannot parse (FILE) as a PDF file" to enable qz pdf printing. // // use pdf method print method of qz @@ -245,12 +244,13 @@ frappe.ui.form.PrintPreview = Class.extend({ // frappe.ui.form.qz_fail(err); // }) } - } - else if(me.is_raw_printing()) { - frappe.show_alert({message:__('Please set a printer mapping for this print format in the QZ Settings'),indicator:'blue'},14); + } else if (me.is_raw_printing()) { + frappe.show_alert({ + message: __('Please set a printer mapping for this print format in the QZ Settings'), + indicator: 'blue' + }, 14); me.qz_setting_dialog(); - } - else { + } else { me.new_page_preview(true); } } @@ -300,13 +300,12 @@ frappe.ui.form.PrintPreview = Class.extend({ } }); }, - get_mapped_printer: function() { - if(localStorage && localStorage.print_format_printer_map - && JSON.parse(localStorage.print_format_printer_map)[this.frm.doctype]) { + get_mapped_printer: function () { + if (localStorage && localStorage.print_format_printer_map && + JSON.parse(localStorage.print_format_printer_map)[this.frm.doctype]) { return (JSON.parse(localStorage.print_format_printer_map)[this.frm.doctype]) - .filter((printer_map)=> printer_map.print_format == this.selected_format()); - } - else { + .filter((printer_map) => printer_map.print_format == this.selected_format()); + } else { return []; } }, @@ -375,7 +374,7 @@ frappe.ui.form.PrintPreview = Class.extend({ set_style: function (style) { frappe.dom.set_style(style || frappe.boot.print_css, "print-style"); }, - qz_setting_dialog: function() { + qz_setting_dialog: function () { var me = this; if (localStorage && localStorage.print_format_printer_map) this.print_format_printer_map = JSON.parse(localStorage.print_format_printer_map); @@ -384,15 +383,16 @@ frappe.ui.form.PrintPreview = Class.extend({ this.data = []; this.data = this.print_format_printer_map[this.frm.doctype] || []; this.printer_list = []; - frappe.ui.form.qz_get_printer_list().then((data)=>{ + frappe.ui.form.qz_get_printer_list().then((data) => { this.printer_list = data; if (!(this.printer_list && this.printer_list.length)) { frappe.throw(__("No Printer is Available.")); } const dialog = new frappe.ui.Dialog({ title: __("QZ Tray Print Settings"), - fields: [ - {fieldtype:'Section Break'}, + fields: [{ + fieldtype: 'Section Break' + }, { fieldname: "printer_mapping", fieldtype: "Table", @@ -403,16 +403,16 @@ frappe.ui.form.PrintPreview = Class.extend({ return this.data; }, fields: [{ - fieldtype:'Select', - fieldname:"print_format", + fieldtype: 'Select', + fieldname: "print_format", default: 0, options: this.print_formats, read_only: 0, in_list_view: 1, label: __('Print Format') }, { - fieldtype:'Select', - fieldname:"printer", + fieldtype: 'Select', + fieldname: "printer", default: 0, options: this.printer_list, read_only: 0, @@ -421,15 +421,14 @@ frappe.ui.form.PrintPreview = Class.extend({ }] }, ], - primary_action: function() { + primary_action: function () { let printer_mapping = this.get_values()["printer_mapping"]; if (printer_mapping && printer_mapping.length) { let print_format_list = printer_mapping.map(a => a.print_format); - let has_duplicate = print_format_list.some((item, idx) => print_format_list.indexOf(item) != idx ); + let has_duplicate = print_format_list.some((item, idx) => print_format_list.indexOf(item) != idx); if (has_duplicate) frappe.throw(__("Cannot have multiple printers mapped to a single print format.")); - } - else { + } else { printer_mapping = []; } if (localStorage && localStorage.print_format_printer_map) @@ -444,7 +443,6 @@ frappe.ui.form.PrintPreview = Class.extend({ }); dialog.show(); }); - } }); @@ -493,59 +491,84 @@ frappe.ui.get_print_settings = function (pdf, callback, letter_head) { // - if connection fails, catch the reject, fire the mimetype launcher // - after mimetype launcher is fired, try to connect 3 more times // - display success/fail meaasges to user -frappe.ui.form.qz_connect = function() { - return new Promise(function(resolve, reject) { - if (qz.websocket.isActive()) { // if already active, resolve immediately +frappe.ui.form.qz_connect = function () { + return new Promise(function (resolve, reject) { + if (qz.websocket.isActive()) { // if already active, resolve immediately // frappe.show_alert({message: __('QZ Tray Connection Active!'), indicator: 'green'}); resolve(); - } - else { + } else { // try to connect once before firing the mimetype launcher - frappe.show_alert({message: __('Attemting Connection to QZ Tray!'), indicator: 'blue'}); - qz.websocket.connect().then(()=>{ - frappe.show_alert({message: __('Connected to QZ Tray!'), indicator: 'green'}); + frappe.show_alert({ + message: __('Attemting Connection to QZ Tray!'), + indicator: 'blue' + }); + qz.websocket.connect().then(() => { + frappe.show_alert({ + message: __('Connected to QZ Tray!'), + indicator: 'green' + }); resolve(); }, function retry(err) { if (err.message === 'Unable to establish connection with QZ') { // if a connect was not succesful, launch the mimetime, try 3 more times - frappe.show_alert({message: __('Attemting to launch QZ Tray!'), indicator: 'blue'},14); + frappe.show_alert({ + message: __('Attemting to launch QZ Tray!'), + indicator: 'blue' + }, 14); window.location.assign("qz:launch"); - qz.websocket.connect({ retries: 3, delay: 1 }).then(()=>{ - frappe.show_alert({message: __('Connected to QZ Tray!'), indicator: 'green'}); - resolve(); - }, - ()=> { - frappe.show_alert({message: __('Error connecting to QZ Tray! Click here to Download QZ Tray'), indicator: 'red'},14); - reject(); - }); - } - else { - frappe.show_alert({message: 'QZ Tray '+err.toString(), indicator: 'red'},14); + qz.websocket.connect({ + retries: 3, + delay: 1 + }).then(() => { + frappe.show_alert({ + message: __('Connected to QZ Tray!'), + indicator: 'green' + }); + resolve(); + }, + () => { + frappe.show_alert({ + message: __('Error connecting to QZ Tray! Click here to Download QZ Tray'), + indicator: 'red' + }, 14); + reject(); + }); + } else { + frappe.show_alert({ + message: 'QZ Tray ' + err.toString(), + indicator: 'red' + }, 14); reject(); } - }); + }); } }); } -frappe.ui.form.qz_get_printer_list = function(){ - return frappe.ui.form.qz_connect().then(function(){ +frappe.ui.form.qz_get_printer_list = function () { + return frappe.ui.form.qz_connect().then(function () { return qz.printers.find(); - }).then((data)=>{ + }).then((data) => { return data; - }).catch((err)=>{ + }).catch((err) => { frappe.ui.form.qz_fail(err); }); } // notify qz successful print -frappe.ui.form.qz_success = function() { - frappe.show_alert({message: __('QZ print complete!'), indicator: 'green'}); +frappe.ui.form.qz_success = function () { + frappe.show_alert({ + message: __('QZ print complete!'), + indicator: 'green' + }); } // notify qz errors -frappe.ui.form.qz_fail = function(e) { - frappe.show_alert({message:__("QZ Tray Failed") + e.toString(), indicator:'red'},20); +frappe.ui.form.qz_fail = function (e) { + frappe.show_alert({ + message: __("QZ Tray Failed") + e.toString(), + indicator: 'red' + }, 20); } @@ -562,4 +585,3 @@ frappe.ui.form.qz_fail = function(e) { // - show modal with list of printer and ask to map // - store in LocalStorage // - else throw error that no printer is available - From 8397383dd6befd3e82102ef74efa8bbd6432238f Mon Sep 17 00:00:00 2001 From: karthikeyan5 Date: Thu, 4 Apr 2019 16:02:58 +0530 Subject: [PATCH 037/299] fix(Raw Printing): fixes as per PR review > fixing confusing naming in the UI and calling it "Raw Print" > used import for sha256 library > changed the Print Preview message for raw print > same possible codacy fixes --- .eslintrc | 3 +- frappe/public/build.json | 1 - frappe/public/js/frappe/form/print.js | 155 +++++++++--------- .../frappe/form/templates/print_layout.html | 4 +- frappe/www/printview.py | 4 +- 5 files changed, 78 insertions(+), 89 deletions(-) diff --git a/.eslintrc b/.eslintrc index 602476f153..3711a7dbe6 100644 --- a/.eslintrc +++ b/.eslintrc @@ -141,7 +141,6 @@ "context": true, "before": true, "beforeEach": true, - "qz": true, - "sha256": true + "qz": true } } diff --git a/frappe/public/build.json b/frappe/public/build.json index bc4db001ac..f4e1cbca9f 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -154,7 +154,6 @@ "public/js/lib/leaflet/leaflet.draw.js", "public/js/lib/leaflet/L.Control.Locate.js", "public/js/lib/leaflet/easy-button.js", - "node_modules/js-sha256/build/sha256.min.js", "node_modules/qz-tray/qz-tray.js" ], "js/desk.min.js": [ diff --git a/frappe/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index fa15c07ebe..8dbbb40a30 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -1,4 +1,5 @@ frappe.provide("frappe.ui.form"); +import sha256 from 'js-sha256'; // init qz tray library qz.api.setPromiseType(function promise(resolver) { @@ -55,8 +56,8 @@ frappe.ui.form.PrintPreview = Class.extend({ me.multilingual_preview() }); - this.wrapper.find(".btn-qz-settings").click(function () { - me.qz_setting_dialog(); + this.wrapper.find(".btn-raw-print-setting").click(function () { + me.raw_print_setting_dialog(); }); this.wrapper.find(".btn-print-print").click(function () { @@ -223,7 +224,7 @@ frappe.ui.form.PrintPreview = Class.extend({ }); } else { frappe.show_alert({ - message: __('PDF Printing via QZ is not yet supported. Please remove QZ printer mapping for this Print format and try again.'), + message: __('PDF printing via "Raw Print" is not yet supported. Please remove the printer mapping in Raw Printing Settings and try again.'), indicator: 'blue' }, 14); //Note: need to solve "Error: Cannot parse (FILE) as a PDF file" to enable qz pdf printing. @@ -246,10 +247,10 @@ frappe.ui.form.PrintPreview = Class.extend({ } } else if (me.is_raw_printing()) { frappe.show_alert({ - message: __('Please set a printer mapping for this print format in the QZ Settings'), + message: __('Please set a printer mapping for this print format in the Raw Printing Settings'), indicator: 'blue' }, 14); - me.qz_setting_dialog(); + me.raw_print_setting_dialog(); } else { me.new_page_preview(true); } @@ -301,14 +302,24 @@ frappe.ui.form.PrintPreview = Class.extend({ }); }, get_mapped_printer: function () { - if (localStorage && localStorage.print_format_printer_map && - JSON.parse(localStorage.print_format_printer_map)[this.frm.doctype]) { - return (JSON.parse(localStorage.print_format_printer_map)[this.frm.doctype]) - .filter((printer_map) => printer_map.print_format == this.selected_format()); - } else { + let print_format_printer_map = get_print_format_printer_map(); + if (print_format_printer_map[this.frm.doctype]) { + return print_format_printer_map[this.frm.doctype].filter( + (printer_map) => printer_map.print_format == this.selected_format()); + } + else { return []; } }, + get_print_format_printer_map: function () { + try { + let print_format_printer_map = JSON.parse(localStorage.print_format_printer_map); + return print_format_printer_map; + } + catch(e) { + return {}; + } + }, preview_old_style: function () { var me = this; this.with_old_style({ @@ -355,7 +366,7 @@ frappe.ui.form.PrintPreview = Class.extend({ return this.get_print_format(format).print_format_type === "Client"; }, is_raw_printing: function (format) { - return this.get_print_format(format).raw_printing === true; + return this.get_print_format(format).raw_printing === 1; }, get_print_format: function (format) { if (!format) { @@ -374,52 +385,46 @@ frappe.ui.form.PrintPreview = Class.extend({ set_style: function (style) { frappe.dom.set_style(style || frappe.boot.print_css, "print-style"); }, - qz_setting_dialog: function () { + raw_print_setting_dialog: function () { var me = this; - if (localStorage && localStorage.print_format_printer_map) - this.print_format_printer_map = JSON.parse(localStorage.print_format_printer_map); - else - this.print_format_printer_map = {}; + this.print_format_printer_map = get_print_format_printer_map(); this.data = []; this.data = this.print_format_printer_map[this.frm.doctype] || []; this.printer_list = []; frappe.ui.form.qz_get_printer_list().then((data) => { this.printer_list = data; - if (!(this.printer_list && this.printer_list.length)) { - frappe.throw(__("No Printer is Available.")); - } const dialog = new frappe.ui.Dialog({ - title: __("QZ Tray Print Settings"), + title: __("Raw Print Settings"), fields: [{ - fieldtype: 'Section Break' - }, - { - fieldname: "printer_mapping", - fieldtype: "Table", - label: __('Printer Mapping'), - in_place_edit: true, - data: this.data, - get_data: () => { - return this.data; - }, - fields: [{ - fieldtype: 'Select', - fieldname: "print_format", - default: 0, - options: this.print_formats, - read_only: 0, - in_list_view: 1, - label: __('Print Format') - }, { - fieldtype: 'Select', - fieldname: "printer", - default: 0, - options: this.printer_list, - read_only: 0, - in_list_view: 1, - label: __('Printer') - }] + fieldtype: 'Section Break' + }, + { + fieldname: "printer_mapping", + fieldtype: "Table", + label: __('Printer Mapping'), + in_place_edit: true, + data: this.data, + get_data: () => { + return this.data; }, + fields: [{ + fieldtype: 'Select', + fieldname: "print_format", + default: 0, + options: this.print_formats, + read_only: 0, + in_list_view: 1, + label: __('Print Format') + }, { + fieldtype: 'Select', + fieldname: "printer", + default: 0, + options: this.printer_list, + read_only: 0, + in_list_view: 1, + label: __('Printer') + }] + }, ], primary_action: function () { let printer_mapping = this.get_values()["printer_mapping"]; @@ -431,10 +436,7 @@ frappe.ui.form.PrintPreview = Class.extend({ } else { printer_mapping = []; } - if (localStorage && localStorage.print_format_printer_map) - this.print_format_printer_map = JSON.parse(localStorage.print_format_printer_map); - else - this.print_format_printer_map = {}; + this.print_format_printer_map = get_print_format_printer_map(); this.print_format_printer_map[me.frm.doctype] = printer_mapping; localStorage.print_format_printer_map = JSON.stringify(this.print_format_printer_map); this.hide(); @@ -442,6 +444,9 @@ frappe.ui.form.PrintPreview = Class.extend({ primary_action_label: __('Save') }); dialog.show(); + if (!(this.printer_list && this.printer_list.length)) { + frappe.throw(__("No Printer is Available.")); + } }); } }); @@ -485,12 +490,12 @@ frappe.ui.get_print_settings = function (pdf, callback, letter_head) { } -// qz connection wrapper +// qz tray connection wrapper // - allows active and inactive connections to resolve regardless // - try to connect once before firing the mimetype launcher // - if connection fails, catch the reject, fire the mimetype launcher // - after mimetype launcher is fired, try to connect 3 more times -// - display success/fail meaasges to user +// - display success/fail message to user frappe.ui.form.qz_connect = function () { return new Promise(function (resolve, reject) { if (qz.websocket.isActive()) { // if already active, resolve immediately @@ -520,19 +525,19 @@ frappe.ui.form.qz_connect = function () { retries: 3, delay: 1 }).then(() => { - frappe.show_alert({ - message: __('Connected to QZ Tray!'), - indicator: 'green' - }); - resolve(); - }, - () => { - frappe.show_alert({ - message: __('Error connecting to QZ Tray! Click here to Download QZ Tray'), - indicator: 'red' - }, 14); - reject(); + frappe.show_alert({ + message: __('Connected to QZ Tray!'), + indicator: 'green' }); + resolve(); + }, + () => { + frappe.show_alert({ + message: __('Error connecting to QZ Tray! Click here to Download QZ Tray'), + indicator: 'red' + }, 14); + reject(); + }); } else { frappe.show_alert({ message: 'QZ Tray ' + err.toString(), @@ -558,7 +563,7 @@ frappe.ui.form.qz_get_printer_list = function () { // notify qz successful print frappe.ui.form.qz_success = function () { frappe.show_alert({ - message: __('QZ print complete!'), + message: __('Print Sent to printer!!'), indicator: 'green' }); } @@ -566,22 +571,8 @@ frappe.ui.form.qz_success = function () { // notify qz errors frappe.ui.form.qz_fail = function (e) { frappe.show_alert({ - message: __("QZ Tray Failed") + e.toString(), + message: __("QZ Tray Failed: ") + e.toString(), indicator: 'red' }, 20); } - -// flow for action after print button is clicked -// - if printer is already mapped in localstorage (applies for both raw and pdf ) -// - qz_connect() -// - search for configured printer and create config -// - if the above fails throw error with printer not found. (and instructions/options to remove all mapping from localstorage for this printer) -// - if raw_printing call appropriate qz fn -// - else call pdf and then call appropriate qz fn with that pdf -// - else if raw_printing == true -// - qz_connect() -// - if search returns printers -// - show modal with list of printer and ask to map -// - store in LocalStorage -// - else throw error that no printer is available diff --git a/frappe/public/js/frappe/form/templates/print_layout.html b/frappe/public/js/frappe/form/templates/print_layout.html index 2457a1ff58..0c15f3d197 100644 --- a/frappe/public/js/frappe/form/templates/print_layout.html +++ b/frappe/public/js/frappe/form/templates/print_layout.html @@ -19,8 +19,8 @@ {%= __("Print") %} {%= __("Settings...") %} - - {%= __("QZ Settings...") %} + + {%= __("Raw Print Settings...") %} {%= __("Customize...") %} diff --git a/frappe/www/printview.py b/frappe/www/printview.py index b7b147f83b..5da86cb225 100644 --- a/frappe/www/printview.py +++ b/frappe/www/printview.py @@ -184,8 +184,8 @@ def get_html_and_style(doc, name=None, print_format=None, meta=None, if print_format and print_format.raw_printing: return { - "html": '
    ' - + _("Note: This Print Format is in Raw Commands and cannot be previewed.") + "html": '
    ' + + _("No Preview Available") + '
    ' } From 68a1a549a145694e153dd873e352f4e89f11c546 Mon Sep 17 00:00:00 2001 From: karthikeyan5 Date: Mon, 8 Apr 2019 18:17:08 +0530 Subject: [PATCH 038/299] fix(raw printing): more codacy fixes --- frappe/public/js/frappe/form/print.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/frappe/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index 8dbbb40a30..1d05b7a620 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -302,7 +302,7 @@ frappe.ui.form.PrintPreview = Class.extend({ }); }, get_mapped_printer: function () { - let print_format_printer_map = get_print_format_printer_map(); + let print_format_printer_map = this.get_print_format_printer_map(); if (print_format_printer_map[this.frm.doctype]) { return print_format_printer_map[this.frm.doctype].filter( (printer_map) => printer_map.print_format == this.selected_format()); @@ -315,8 +315,7 @@ frappe.ui.form.PrintPreview = Class.extend({ try { let print_format_printer_map = JSON.parse(localStorage.print_format_printer_map); return print_format_printer_map; - } - catch(e) { + } catch (e) { return {}; } }, @@ -387,7 +386,7 @@ frappe.ui.form.PrintPreview = Class.extend({ }, raw_print_setting_dialog: function () { var me = this; - this.print_format_printer_map = get_print_format_printer_map(); + this.print_format_printer_map = me.get_print_format_printer_map(); this.data = []; this.data = this.print_format_printer_map[this.frm.doctype] || []; this.printer_list = []; @@ -436,7 +435,7 @@ frappe.ui.form.PrintPreview = Class.extend({ } else { printer_mapping = []; } - this.print_format_printer_map = get_print_format_printer_map(); + this.print_format_printer_map = me.get_print_format_printer_map(); this.print_format_printer_map[me.frm.doctype] = printer_mapping; localStorage.print_format_printer_map = JSON.stringify(this.print_format_printer_map); this.hide(); @@ -563,7 +562,7 @@ frappe.ui.form.qz_get_printer_list = function () { // notify qz successful print frappe.ui.form.qz_success = function () { frappe.show_alert({ - message: __('Print Sent to printer!!'), + message: __('Print Sent to printer!'), indicator: 'green' }); } From 41fa04871834e5f69238d2f85d7bd0b0fc7aa222 Mon Sep 17 00:00:00 2001 From: karthikeyan5 Date: Wed, 10 Apr 2019 17:34:16 +0530 Subject: [PATCH 039/299] feat(Raw Printing): added "Enable Raw Printing" > added more comments in code --- .../print_settings/print_settings.json | 1661 +++++++++-------- frappe/public/js/frappe/form/print.js | 11 +- .../frappe/form/templates/print_layout.html | 2 +- frappe/public/js/frappe/model/meta.js | 4 +- 4 files changed, 887 insertions(+), 791 deletions(-) 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/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index 1d05b7a620..01696a9132 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -20,6 +20,9 @@ frappe.ui.form.PrintPreview = Class.extend({ // only system manager can edit this.wrapper.find(".btn-print-edit").toggle(frappe.user.has_role("System Manager")); + if (frappe.model.get_doc(":Print Settings", "Print Settings").enable_raw_printing == "1") { + this.wrapper.find(".btn-raw-print-setting").toggle(true); + } }, bind_events: function () { var me = this; @@ -246,6 +249,7 @@ frappe.ui.form.PrintPreview = Class.extend({ // }) } } else if (me.is_raw_printing()) { + // printer not mapped in localstorage and the current print format is raw printing frappe.show_alert({ message: __('Please set a printer mapping for this print format in the Raw Printing Settings'), indicator: 'blue' @@ -287,6 +291,7 @@ frappe.ui.form.PrintPreview = Class.extend({ }); }, get_raw_commands: function (callback) { + // fetches rendered raw commands from the server for the current print format. frappe.call({ method: "frappe.www.printview.get_rendered_raw_commands", args: { @@ -302,16 +307,17 @@ frappe.ui.form.PrintPreview = Class.extend({ }); }, get_mapped_printer: function () { + // returns a list of "print format: printer" mapping filtered by the current print format let print_format_printer_map = this.get_print_format_printer_map(); if (print_format_printer_map[this.frm.doctype]) { return print_format_printer_map[this.frm.doctype].filter( (printer_map) => printer_map.print_format == this.selected_format()); - } - else { + } else { return []; } }, get_print_format_printer_map: function () { + // returns the whole object "print_format_printer_map" stored in the localStorage. try { let print_format_printer_map = JSON.parse(localStorage.print_format_printer_map); return print_format_printer_map; @@ -385,6 +391,7 @@ frappe.ui.form.PrintPreview = Class.extend({ frappe.dom.set_style(style || frappe.boot.print_css, "print-style"); }, raw_print_setting_dialog: function () { + // dialog for the Raw Print Settings var me = this; this.print_format_printer_map = me.get_print_format_printer_map(); this.data = []; diff --git a/frappe/public/js/frappe/form/templates/print_layout.html b/frappe/public/js/frappe/form/templates/print_layout.html index 0c15f3d197..adb90ae2c7 100644 --- a/frappe/public/js/frappe/form/templates/print_layout.html +++ b/frappe/public/js/frappe/form/templates/print_layout.html @@ -19,7 +19,7 @@ {%= __("Print") %}
    {%= __("Settings...") %} - + {%= __("Customize...") %} diff --git a/frappe/public/js/frappe/model/meta.js b/frappe/public/js/frappe/model/meta.js index 4ecb4541fc..f16a1401a1 100644 --- a/frappe/public/js/frappe/model/meta.js +++ b/frappe/public/js/frappe/model/meta.js @@ -196,11 +196,11 @@ $.extend(frappe.meta, { get_print_formats: function(doctype) { var print_format_list = ["Standard"]; var default_print_format = locals.DocType[doctype].default_print_format; - + let enable_raw_printing = frappe.model.get_doc(":Print Settings", "Print Settings").enable_raw_printing; var print_formats = frappe.get_list("Print Format", {doc_type: doctype}) .sort(function(a, b) { return (a > b) ? 1 : -1; }); $.each(print_formats, function(i, d) { - if(!in_list(print_format_list, d.name) && in_list(['Server', 'Client'], d.print_format_type)) + if(!in_list(print_format_list, d.name) && in_list(['Server', 'Client'], d.print_format_type) && (cint(enable_raw_printing) || !d.raw_printing)) print_format_list.push(d.name); }); From 2c9f5aeb90212147d3898092f365890249c53195 Mon Sep 17 00:00:00 2001 From: karthikeyan5 Date: Mon, 15 Apr 2019 16:54:14 +0530 Subject: [PATCH 040/299] feat(Raw Printing): added help text in UI --- .../doctype/print_format/print_format.json | 32 ++++++++++++++++--- frappe/public/js/frappe/form/print.js | 7 ++-- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/frappe/printing/doctype/print_format/print_format.json b/frappe/printing/doctype/print_format/print_format.json index 1d96d9f0c7..852f378a53 100644 --- a/frappe/printing/doctype/print_format/print_format.json +++ b/frappe/printing/doctype/print_format/print_format.json @@ -21,6 +21,7 @@ "collapsible": 0, "columns": 0, "description": "", + "fetch_if_empty": 0, "fieldname": "doc_type", "fieldtype": "Link", "hidden": 0, @@ -53,6 +54,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "module", "fieldtype": "Link", "hidden": 0, @@ -86,6 +88,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "disabled", "fieldtype": "Check", "hidden": 0, @@ -117,6 +120,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_3", "fieldtype": "Column Break", "hidden": 0, @@ -148,6 +152,7 @@ "collapsible": 0, "columns": 0, "default": "No", + "fetch_if_empty": 0, "fieldname": "standard", "fieldtype": "Select", "hidden": 0, @@ -182,6 +187,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "custom_format", "fieldtype": "Check", "hidden": 0, @@ -215,6 +221,7 @@ "collapsible": 0, "columns": 0, "depends_on": "custom_format", + "fetch_if_empty": 0, "fieldname": "section_break_6", "fieldtype": "Section Break", "hidden": 0, @@ -248,6 +255,7 @@ "default": "Server", "depends_on": "custom_format", "description": "", + "fetch_if_empty": 0, "fieldname": "print_format_type", "fieldtype": "Select", "hidden": 0, @@ -281,6 +289,7 @@ "collapsible": 0, "columns": 0, "depends_on": "", + "fetch_if_empty": 0, "fieldname": "raw_printing", "fieldtype": "Check", "hidden": 0, @@ -314,6 +323,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.raw_printing", + "fetch_if_empty": 0, "fieldname": "html", "fieldtype": "Code", "hidden": 0, @@ -349,6 +359,8 @@ "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, @@ -382,6 +394,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.custom_format", + "fetch_if_empty": 0, "fieldname": "section_break_9", "fieldtype": "Section Break", "hidden": 0, @@ -415,6 +428,7 @@ "collapsible": 0, "columns": 0, "default": "0", + "fetch_if_empty": 0, "fieldname": "align_labels_right", "fieldtype": "Check", "hidden": 0, @@ -448,6 +462,7 @@ "collapsible": 0, "columns": 0, "default": "0", + "fetch_if_empty": 0, "fieldname": "show_section_headings", "fieldtype": "Check", "hidden": 0, @@ -481,6 +496,7 @@ "collapsible": 0, "columns": 0, "default": "0", + "fetch_if_empty": 0, "fieldname": "line_breaks", "fieldtype": "Check", "hidden": 0, @@ -513,6 +529,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_11", "fieldtype": "Column Break", "hidden": 0, @@ -544,6 +561,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "default_print_language", "fieldtype": "Link", "hidden": 0, @@ -579,6 +597,7 @@ "columns": 0, "default": "Default", "depends_on": "eval:!doc.custom_format", + "fetch_if_empty": 0, "fieldname": "font", "fieldtype": "Select", "hidden": 0, @@ -613,6 +632,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.raw_printing", + "fetch_if_empty": 0, "fieldname": "css_section", "fieldtype": "Section Break", "hidden": 0, @@ -644,6 +664,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "css", "fieldtype": "Code", "hidden": 0, @@ -676,6 +697,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "custom_html_help", "fieldtype": "HTML", "hidden": 0, @@ -710,6 +732,7 @@ "collapsible": 0, "columns": 0, "depends_on": "custom_format", + "fetch_if_empty": 0, "fieldname": "section_break_13", "fieldtype": "Section Break", "hidden": 0, @@ -742,6 +765,7 @@ "collapsible": 0, "columns": 0, "depends_on": "custom_format", + "fetch_if_empty": 0, "fieldname": "print_format_help", "fieldtype": "HTML", "hidden": 0, @@ -774,6 +798,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "format_data", "fieldtype": "Code", "hidden": 1, @@ -806,6 +831,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "print_format_builder", "fieldtype": "Check", "hidden": 1, @@ -833,17 +859,16 @@ } ], "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": "2019-03-01 12:25:31.874685", + "menu_index": 0, + "modified": "2019-04-15 16:29:06.453546", "modified_by": "Administrator", "module": "Printing", "name": "Print Format", @@ -871,7 +896,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/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index 01696a9132..4284ed65c0 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -538,10 +538,7 @@ frappe.ui.form.qz_connect = function () { resolve(); }, () => { - frappe.show_alert({ - message: __('Error connecting to QZ Tray! Click here to Download QZ Tray'), - indicator: 'red' - }, 14); + frappe.throw(__('Error connecting to QZ Tray Application!

    You need to have QZ Tray application installed and running, to use the Raw Print feature.

    Click here to Download and install QZ Tray.
    Click here to learn more about Raw Printing.')); reject(); }); } else { @@ -569,7 +566,7 @@ frappe.ui.form.qz_get_printer_list = function () { // notify qz successful print frappe.ui.form.qz_success = function () { frappe.show_alert({ - message: __('Print Sent to printer!'), + message: __('Print Sent to the printer!'), indicator: 'green' }); } From 2ec7c5132b4a3c4e49284a40c4061b69318d8d3b Mon Sep 17 00:00:00 2001 From: karthikeyan5 Date: Tue, 16 Apr 2019 14:06:27 +0530 Subject: [PATCH 041/299] fix(Raw Printing): fixes as per PR review 2 > qz-tray.js and sha256.min.js are loaded only on demand > renamed 'raw print settings' button to 'Printer Settings' > removed commented code > fixed spelling mistakes --- frappe/public/build.json | 3 +- frappe/public/js/frappe/form/print.js | 164 +++++++++--------- .../frappe/form/templates/print_layout.html | 4 +- 3 files changed, 88 insertions(+), 83 deletions(-) diff --git a/frappe/public/build.json b/frappe/public/build.json index f4e1cbca9f..620b360f47 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -153,8 +153,7 @@ "public/js/lib/leaflet/leaflet.js", "public/js/lib/leaflet/leaflet.draw.js", "public/js/lib/leaflet/L.Control.Locate.js", - "public/js/lib/leaflet/easy-button.js", - "node_modules/qz-tray/qz-tray.js" + "public/js/lib/leaflet/easy-button.js" ], "js/desk.min.js": [ "public/js/frappe/class.js", diff --git a/frappe/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index 4284ed65c0..2068682b6a 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -1,13 +1,4 @@ frappe.provide("frappe.ui.form"); -import sha256 from 'js-sha256'; - -// init qz tray library -qz.api.setPromiseType(function promise(resolver) { - return new Promise(resolver); -}); -qz.api.setSha256Type(function (data) { - return sha256(data); -}); frappe.ui.form.PrintPreview = Class.extend({ init: function (opts) { @@ -21,7 +12,7 @@ frappe.ui.form.PrintPreview = Class.extend({ // only system manager can edit this.wrapper.find(".btn-print-edit").toggle(frappe.user.has_role("System Manager")); if (frappe.model.get_doc(":Print Settings", "Print Settings").enable_raw_printing == "1") { - this.wrapper.find(".btn-raw-print-setting").toggle(true); + this.wrapper.find(".btn-printer-setting").toggle(true); } }, bind_events: function () { @@ -59,8 +50,8 @@ frappe.ui.form.PrintPreview = Class.extend({ me.multilingual_preview() }); - this.wrapper.find(".btn-raw-print-setting").click(function () { - me.raw_print_setting_dialog(); + this.wrapper.find(".btn-printer-setting").click(function () { + me.printer_setting_dialog(); }); this.wrapper.find(".btn-print-print").click(function () { @@ -216,10 +207,10 @@ frappe.ui.form.PrintPreview = Class.extend({ // printer is already mapped in localstorage (applies for both raw and pdf ) if (me.is_raw_printing()) { me.get_raw_commands(function (out) { - let printer_map = me.get_mapped_printer()[0]; - let config = qz.configs.create(printer_map.printer); - let data = [out.raw_commands]; frappe.ui.form.qz_connect().then(function () { + let printer_map = me.get_mapped_printer()[0]; + let data = [out.raw_commands]; + let config = qz.configs.create(printer_map.printer); return qz.print(config, data); }).then(frappe.ui.form.qz_success).catch((err) => { frappe.ui.form.qz_fail(err); @@ -227,34 +218,18 @@ frappe.ui.form.PrintPreview = Class.extend({ }); } else { frappe.show_alert({ - message: __('PDF printing via "Raw Print" is not yet supported. Please remove the printer mapping in Raw Printing Settings and try again.'), + message: __('PDF printing via "Raw Print" is not yet supported. Please remove the printer mapping in Printer Settings and try again.'), indicator: 'blue' }, 14); //Note: need to solve "Error: Cannot parse (FILE) as a PDF file" to enable qz pdf printing. - - // // use pdf method print method of qz - // let printer_map = me.get_mapped_printer()[0] - // let config = qz.configs.create(printer_map.printer) - // let pdf_url = frappe.urllib.get_full_url("/api/method/frappe.utils.print_format.download_pdf?" - // + "doctype=" + encodeURIComponent(me.frm.doc.doctype) - // + "&name=" + encodeURIComponent(me.frm.doc.name) - // + "&format=" + me.selected_format() - // + "&no_letterhead=" + (me.with_letterhead() ? "0" : "1") - // + (me.lang_code ? ("&_lang=" + me.lang_code) : "")) - // let data = [{type: 'pdf', data: pdf_url}] - // frappe.ui.form.qz_connect().then(function(){ - // return qz.print(config,data); - // }).then(frappe.ui.form.qz_success).catch((err)=>{ - // frappe.ui.form.qz_fail(err); - // }) } } else if (me.is_raw_printing()) { // printer not mapped in localstorage and the current print format is raw printing frappe.show_alert({ - message: __('Please set a printer mapping for this print format in the Raw Printing Settings'), + message: __('Please set a printer mapping for this print format in the Printer Settings'), indicator: 'blue' }, 14); - me.raw_print_setting_dialog(); + me.printer_setting_dialog(); } else { me.new_page_preview(true); } @@ -390,8 +365,8 @@ frappe.ui.form.PrintPreview = Class.extend({ set_style: function (style) { frappe.dom.set_style(style || frappe.boot.print_css, "print-style"); }, - raw_print_setting_dialog: function () { - // dialog for the Raw Print Settings + printer_setting_dialog: function () { + // dialog for the Printer Settings var me = this; this.print_format_printer_map = me.get_print_format_printer_map(); this.data = []; @@ -400,7 +375,7 @@ frappe.ui.form.PrintPreview = Class.extend({ frappe.ui.form.qz_get_printer_list().then((data) => { this.printer_list = data; const dialog = new frappe.ui.Dialog({ - title: __("Raw Print Settings"), + title: __("Printer Settings"), fields: [{ fieldtype: 'Section Break' }, @@ -504,56 +479,87 @@ frappe.ui.get_print_settings = function (pdf, callback, letter_head) { // - display success/fail message to user frappe.ui.form.qz_connect = function () { return new Promise(function (resolve, reject) { - if (qz.websocket.isActive()) { // if already active, resolve immediately - // frappe.show_alert({message: __('QZ Tray Connection Active!'), indicator: 'green'}); + frappe.ui.form.qz_init().then(() => { + if (qz.websocket.isActive()) { // if already active, resolve immediately + // frappe.show_alert({message: __('QZ Tray Connection Active!'), indicator: 'green'}); + resolve(); + } else { + // try to connect once before firing the mimetype launcher + frappe.show_alert({ + message: __('Attempting Connection to QZ Tray...'), + indicator: 'blue' + }); + qz.websocket.connect().then(() => { + frappe.show_alert({ + message: __('Connected to QZ Tray!'), + indicator: 'green' + }); + resolve(); + }, function retry(err) { + if (err.message === 'Unable to establish connection with QZ') { + // if a connect was not successful, launch the mimetype, try 3 more times + frappe.show_alert({ + message: __('Attempting to launch QZ Tray...'), + indicator: 'blue' + }, 14); + window.location.assign("qz:launch"); + qz.websocket.connect({ + retries: 3, + delay: 1 + }).then(() => { + frappe.show_alert({ + message: __('Connected to QZ Tray!'), + indicator: 'green' + }); + resolve(); + }, + () => { + frappe.throw(__('Error connecting to QZ Tray Application...

    You need to have QZ Tray application installed and running, to use the Raw Print feature.

    Click here to Download and install QZ Tray.
    Click here to learn more about Raw Printing.')); + reject(); + }); + } else { + frappe.show_alert({ + message: 'QZ Tray ' + err.toString(), + indicator: 'red' + }, 14); + reject(); + } + }); + } + }); + }); +} + +frappe.ui.form.qz_init = function () { + // Initializing qz tray library + return new Promise((resolve) => { + if (typeof qz === "object" && typeof qz.version === "string") { + // resolve immediately if already Initialized resolve(); } else { - // try to connect once before firing the mimetype launcher - frappe.show_alert({ - message: __('Attemting Connection to QZ Tray!'), - indicator: 'blue' - }); - qz.websocket.connect().then(() => { - frappe.show_alert({ - message: __('Connected to QZ Tray!'), - indicator: 'green' + let qz_required_assets = [ + "/assets/frappe/node_modules/js-sha256/build/sha256.min.js", + "/assets/frappe/node_modules/qz-tray/qz-tray.js" + ]; + frappe.require(qz_required_assets,() => { + qz.api.setPromiseType(function promise(resolver) { + return new Promise(resolver); + }); + qz.api.setSha256Type(function (data) { + // Codacy fix + /*global sha256*/ + return sha256(data); }); resolve(); - }, function retry(err) { - if (err.message === 'Unable to establish connection with QZ') { - // if a connect was not succesful, launch the mimetime, try 3 more times - frappe.show_alert({ - message: __('Attemting to launch QZ Tray!'), - indicator: 'blue' - }, 14); - window.location.assign("qz:launch"); - qz.websocket.connect({ - retries: 3, - delay: 1 - }).then(() => { - frappe.show_alert({ - message: __('Connected to QZ Tray!'), - indicator: 'green' - }); - resolve(); - }, - () => { - frappe.throw(__('Error connecting to QZ Tray Application!

    You need to have QZ Tray application installed and running, to use the Raw Print feature.

    Click here to Download and install QZ Tray.
    Click here to learn more about Raw Printing.')); - reject(); - }); - } else { - frappe.show_alert({ - message: 'QZ Tray ' + err.toString(), - indicator: 'red' - }, 14); - reject(); - } }); + // note 'frappe.require' does not have callback on fail. Hence, any failure cannot be communicated to the user. } + }); } frappe.ui.form.qz_get_printer_list = function () { + // returns the list of printers that are available to the QZ Tray return frappe.ui.form.qz_connect().then(function () { return qz.printers.find(); }).then((data) => { @@ -563,16 +569,16 @@ frappe.ui.form.qz_get_printer_list = function () { }); } -// notify qz successful print frappe.ui.form.qz_success = function () { + // notify qz successful print frappe.show_alert({ message: __('Print Sent to the printer!'), indicator: 'green' }); } -// notify qz errors frappe.ui.form.qz_fail = function (e) { + // notify qz errors frappe.show_alert({ message: __("QZ Tray Failed: ") + e.toString(), indicator: 'red' diff --git a/frappe/public/js/frappe/form/templates/print_layout.html b/frappe/public/js/frappe/form/templates/print_layout.html index adb90ae2c7..5446ea6425 100644 --- a/frappe/public/js/frappe/form/templates/print_layout.html +++ b/frappe/public/js/frappe/form/templates/print_layout.html @@ -19,8 +19,8 @@ {%= __("Print") %} {%= __("Settings...") %} - + {%= __("Customize...") %} From 06bc50b86253b70a8200996b0f9c3e902109b464 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 16 Apr 2019 15:52:39 +0530 Subject: [PATCH 042/299] feat: Full Width Container Persistent using localStorage since container width should be per device --- frappe/public/js/frappe/desk.js | 5 +++++ frappe/public/js/frappe/ui/toolbar/navbar.html | 5 ++++- frappe/public/js/frappe/ui/toolbar/toolbar.js | 15 ++++++++++++++- frappe/public/less/desk.less | 10 +++++++++- rollup/frappe-html-plugin.js | 2 +- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index db85dce81f..9c5bbf8e7e 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(); @@ -507,6 +508,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) { diff --git a/frappe/public/js/frappe/ui/toolbar/navbar.html b/frappe/public/js/frappe/ui/toolbar/navbar.html index 953cf80372..908cb04491 100644 --- a/frappe/public/js/frappe/ui/toolbar/navbar.html +++ b/frappe/public/js/frappe/ui/toolbar/navbar.html @@ -21,7 +21,7 @@ onclick="return false;"> {{ avatar }} + {%= __('Settings') %} +