From fb14ea41e8fa5d0eb4706ee3dccf2dc2fa44305a Mon Sep 17 00:00:00 2001 From: ci2014 Date: Sun, 30 Jul 2017 21:31:28 +0200 Subject: [PATCH 01/69] Update quick_entry.js Add init_callback, for having a callback, when the dialog is rendered and having the ability to use client side scripting for quick entry forms. --- frappe/public/js/frappe/form/quick_entry.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index 299f14176d..d80cbb9cb2 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -1,6 +1,6 @@ frappe.provide('frappe.ui.form'); -frappe.ui.form.make_quick_entry = (doctype, after_insert) => { +frappe.ui.form.make_quick_entry = (doctype, after_insert, init_callback) => { var trimmed_doctype = doctype.replace(/ /g, ''); var controller_name = "QuickEntryForm"; @@ -8,7 +8,7 @@ frappe.ui.form.make_quick_entry = (doctype, after_insert) => { controller_name = trimmed_doctype + "QuickEntryForm"; } - frappe.quick_entry = new frappe.ui.form[controller_name](doctype, after_insert); + frappe.quick_entry = new frappe.ui.form[controller_name](doctype, after_insert, init_callback); return frappe.quick_entry.setup(); }; @@ -16,6 +16,7 @@ frappe.ui.form.QuickEntryForm = Class.extend({ init: function(doctype, after_insert){ this.doctype = doctype; this.after_insert = after_insert; + this.init_callback = init_callback; }, setup: function() { @@ -106,6 +107,10 @@ frappe.ui.form.QuickEntryForm = Class.extend({ this.dialog.onhide = () => frappe.quick_entry = null; this.dialog.show(); this.set_defaults(); + + if (this.init_callback) { + this.init_callback(this.dialog); + } }, register_primary_action: function(){ @@ -141,7 +146,7 @@ frappe.ui.form.QuickEntryForm = Class.extend({ frappe.ui.form.update_calling_link(me.dialog.doc); } else { if(me.after_insert) { - me.after_insert(me.dialig.doc); + me.after_insert(me.dialog.doc); } else { me.open_from_if_not_list(); } From d7646e3a5a9d5e60f7505aff4c11d8f3e22b940b Mon Sep 17 00:00:00 2001 From: ci2014 Date: Sun, 30 Jul 2017 21:49:22 +0200 Subject: [PATCH 02/69] Update create_new.js Add init_callback for new_doc --- frappe/public/js/frappe/model/create_new.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/model/create_new.js b/frappe/public/js/frappe/model/create_new.js index a25c3e70ca..bf2b8fd05b 100644 --- a/frappe/public/js/frappe/model/create_new.js +++ b/frappe/public/js/frappe/model/create_new.js @@ -314,7 +314,7 @@ $.extend(frappe.model, { }); frappe.create_routes = {}; -frappe.new_doc = function (doctype, opts) { +frappe.new_doc = function (doctype, opts, init_callback) { return new Promise(resolve => { if(opts && $.isPlainObject(opts)) { frappe.route_options = opts; @@ -324,7 +324,7 @@ frappe.new_doc = function (doctype, opts) { frappe.set_route(frappe.create_routes[doctype]) .then(() => resolve()); } else { - frappe.ui.form.make_quick_entry(doctype) + frappe.ui.form.make_quick_entry(doctype, null, init_callback) .then(() => resolve()); } }); From 5e61a2c07eb0fd14a20de15a0bf31bc63333535e Mon Sep 17 00:00:00 2001 From: ci2014 Date: Sun, 30 Jul 2017 22:06:35 +0200 Subject: [PATCH 03/69] Update quick_entry.js Add missing init_callback in constructor --- frappe/public/js/frappe/form/quick_entry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index d80cbb9cb2..025f0bba7b 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -13,7 +13,7 @@ frappe.ui.form.make_quick_entry = (doctype, after_insert, init_callback) => { }; frappe.ui.form.QuickEntryForm = Class.extend({ - init: function(doctype, after_insert){ + init: function(doctype, after_insert, init_callback){ this.doctype = doctype; this.after_insert = after_insert; this.init_callback = init_callback; From aa370aef36de1ac920786e11b51c90047aeb30e3 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 10 Aug 2017 11:02:36 +0530 Subject: [PATCH 04/69] [tests] less verbose logs --- .travis.yml | 4 ++-- frappe/app.py | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ab46e06c3d..ef03adb693 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,6 +52,6 @@ before_script: script: - set -e - - bench --verbose run-tests + - bench run-tests - sleep 5 - - bench --verbose run-ui-tests --app frappe + - bench run-ui-tests --app frappe diff --git a/frappe/app.py b/frappe/app.py index 69c90c97ad..eb42948cfd 100644 --- a/frappe/app.py +++ b/frappe/app.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import os import MySQLdb from six import iteritems +import logging from werkzeug.wrappers import Request from werkzeug.local import LocalManager @@ -225,6 +226,10 @@ def serve(port=8000, profile=False, site=None, sites_path='.'): } in_test_env = os.environ.get('CI') + if in_test_env: + log = logging.getLogger('werkzeug') + log.setLevel(logging.ERROR) + run_simple('0.0.0.0', int(port), application, use_reloader=not in_test_env, use_debugger=not in_test_env, From 6081c30971678d2ba1c8d69e989607ca5efa370d Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 10 Aug 2017 11:11:04 +0530 Subject: [PATCH 05/69] [tests] less verbose logs --- frappe/tests/ui/test_test_runner.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frappe/tests/ui/test_test_runner.py b/frappe/tests/ui/test_test_runner.py index fec5a20d82..3c54731fb1 100644 --- a/frappe/tests/ui/test_test_runner.py +++ b/frappe/tests/ui/test_test_runner.py @@ -27,12 +27,12 @@ class TestTestRunner(unittest.TestCase): driver.click_primary_action() driver.wait_for('#frappe-qunit-done', timeout=timeout) console = driver.get_console() - if frappe.flags.tests_verbose or True: + passed = 'Tests Passed' in console + if frappe.flags.tests_verbose or not passed: for line in console: print(line) - print('-' * 40) - print('Checking if passed "{0}"'.format(test)) - self.assertTrue('Tests Passed' in console) + print('-' * 40) + self.assertTrue(passed) time.sleep(1) frappe.db.set_default('in_selenium', None) driver.close() From 7954ea453c00e749eb46d131c178feb6cb468585 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 10 Aug 2017 11:50:22 +0530 Subject: [PATCH 06/69] [tests] less verbose logs --- frappe/utils/background_jobs.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index 694195a438..27710cef8e 100755 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals, print_function import redis from rq import Connection, Queue, Worker +from rq.logutils import setup_loghandlers from frappe.utils import cstr from collections import defaultdict import frappe @@ -102,6 +103,9 @@ def start_worker(queue=None): # empty init is required to get redis_queue from common_site_config.json redis_connection = get_redis_conn() + if os.environ.get('CI'): + setup_loghandlers('ERROR') + with Connection(redis_connection): queues = get_queue_list(queue) Worker(queues, name=get_worker_name(queue)).work() From e42df8a180cc66eee3aeeb141590e7d5851b5d1b Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 10 Aug 2017 11:55:34 +0530 Subject: [PATCH 07/69] [tests] ignore if docinfo not loaded --- frappe/public/js/frappe/form/form_viewers.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/form/form_viewers.js b/frappe/public/js/frappe/form/form_viewers.js index b29ceb7584..f6bd8b847a 100644 --- a/frappe/public/js/frappe/form/form_viewers.js +++ b/frappe/public/js/frappe/form/form_viewers.js @@ -4,11 +4,18 @@ frappe.ui.form.Viewers = Class.extend({ init: function(opts) { $.extend(this, opts); }, + get_viewers: function() { + let docinfo = this.frm.get_docinfo(); + if (docinfo) { + return docinfo.viewers || {}; + } else { + return {}; + } + }, refresh: function(data_updated) { - var me = this; this.parent.empty(); - var viewers = this.frm.get_docinfo().viewers || {}; + var viewers = this.get_viewers(); var users = []; var new_users = []; @@ -55,7 +62,8 @@ frappe.ui.form.Viewers = Class.extend({ frappe.ui.form.set_viewers = function(data) { var doctype = data.doctype; var docname = data.docname; - var past_viewers = (frappe.model.get_docinfo(doctype, docname).viewers || {}).past || []; + var docinfo = frappe.model.get_docinfo(doctype, docname); + var past_viewers = ((docinfo && docinfo.viewers) || {}).past || []; var viewers = data.viewers || []; var new_viewers = viewers.filter(viewer => !past_viewers.includes(viewer)); From c445047d1c330dc6d16d76755f976aff491bf8bc Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 10 Aug 2017 11:58:57 +0530 Subject: [PATCH 08/69] [fix] dont watch in CI --- frappe/commands/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index 74da084beb..219cdc9898 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -18,6 +18,8 @@ def build(make_copy=False, verbose=False): @click.command('watch') def watch(): "Watch and concatenate JS and CSS files as and when they change" + if os.environ.get('CI'): + return import frappe.build frappe.init('') frappe.build.watch(True) From 477b50bbb1fd18f774c4588d92e5ac86e49bfd02 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 10 Aug 2017 13:06:12 +0530 Subject: [PATCH 09/69] Fix date cached between forms --- frappe/public/js/frappe/form/control.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js index f979bb2cb5..fa738c8190 100755 --- a/frappe/public/js/frappe/form/control.js +++ b/frappe/public/js/frappe/form/control.js @@ -744,9 +744,24 @@ frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({ }, set_formatted_input: function(value) { this._super(value); - if(value - && ((this.last_value && this.last_value !== value) - || (!this.datepicker.selectedDates.length))) { + if(!value) return; + + let should_refresh = this.last_value && this.last_value !== value; + + if (!should_refresh) { + if(this.datepicker.selectedDates.length > 0) { + // if date is selected but different from value, refresh + const selected_date = + moment(this.datepicker.selectedDates[0]) + .format(moment.defaultDateFormat); + should_refresh = selected_date !== value; + } else { + // if datepicker has no selected date, refresh + should_refresh = true; + } + } + + if(should_refresh) { this.datepicker.selectDate(frappe.datetime.str_to_obj(value)); } }, From f4700957fa810b3d23097129029dcc3758cb92a7 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 10 Aug 2017 14:16:34 +0530 Subject: [PATCH 10/69] [fix] dont watch in CI --- frappe/commands/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index 219cdc9898..139529a08f 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -18,8 +18,8 @@ def build(make_copy=False, verbose=False): @click.command('watch') def watch(): "Watch and concatenate JS and CSS files as and when they change" - if os.environ.get('CI'): - return + # if os.environ.get('CI'): + # return import frappe.build frappe.init('') frappe.build.watch(True) From 9785e925b78149d2d5686c8e7dfbe2fd829c0340 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 10 Aug 2017 14:55:04 +0530 Subject: [PATCH 11/69] [fix] for ci --- frappe/utils/background_jobs.py | 3 +++ requirements.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index 27710cef8e..e9c0bc8406 100755 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -54,6 +54,9 @@ def execute_job(site, method, event, job_name, kwargs, user=None, async=True, re if async: frappe.connect(site) + if os.environ.get('CI'): + frappe.flags.in_test = True + if user: frappe.set_user(user) diff --git a/requirements.txt b/requirements.txt index 0f6a4ef421..4dfaa5f9c5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,6 +34,9 @@ beautifulsoup4 rq schedule cryptography +pyopenssl +ndg-httpsclient +pyasn1 zxcvbn psutil unittest-xml-reporting From 43c16d1e72921fb69eee3b0fe00dc7e45df1a62c Mon Sep 17 00:00:00 2001 From: KanchanChauhan Date: Thu, 10 Aug 2017 15:09:49 +0530 Subject: [PATCH 12/69] Activate primary action on Enter in dialog (#3895) --- frappe/public/js/frappe/ui/keyboard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/ui/keyboard.js b/frappe/public/js/frappe/ui/keyboard.js index f4a780a78b..aa042e7a7a 100644 --- a/frappe/public/js/frappe/ui/keyboard.js +++ b/frappe/public/js/frappe/ui/keyboard.js @@ -68,7 +68,7 @@ frappe.ui.keys.on('esc', function(e) { close_grid_and_dialog(); }); -frappe.ui.keys.on('Enter', function(e) { +frappe.ui.keys.on('enter', function(e) { if(cur_dialog && cur_dialog.confirm_dialog) { cur_dialog.get_primary_btn().trigger('click'); } From 3e52f44a791bf05bf371012d16c293ae021c3cf1 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 10 Aug 2017 16:09:08 +0530 Subject: [PATCH 13/69] [minor] contact.js --- frappe/contacts/doctype/contact/contact.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/contacts/doctype/contact/contact.js b/frappe/contacts/doctype/contact/contact.js index d44904d9d5..109b971430 100644 --- a/frappe/contacts/doctype/contact/contact.js +++ b/frappe/contacts/doctype/contact/contact.js @@ -18,7 +18,7 @@ frappe.ui.form.on("Contact", { if(!frm.doc.user && !frm.is_new() && frm.perm[0].write) { frm.add_custom_button(__("Invite as User"), function() { - frappe.call({ + return frappe.call({ method: "frappe.contacts.doctype.contact.contact.invite_user", args: { contact: frm.doc.name From d1a9f0194ca822e2d72f4f24ce3f8bc590eef76d Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 10 Aug 2017 16:11:18 +0530 Subject: [PATCH 14/69] Show totals row always in query report --- .../js/frappe/views/reports/query_report.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index d5bc9a05e5..03ccd03ecc 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -594,6 +594,7 @@ frappe.views.QueryReport = Class.extend({ var me = this; this.dataView.onRowCountChanged.subscribe(function (e, args) { + me.update_totals_row(e, args); me.grid.updateRowCount(); me.grid.render(); }); @@ -603,8 +604,38 @@ frappe.views.QueryReport = Class.extend({ me.grid.render(); }); }, + update_totals_row: function(e, args) { + if(!this.report_doc.add_total_row) return; + + const data_length = this.dataView.getLength(); + const last_index = data_length - 1; + + const number_fields = ['Currency', 'Float', 'Int']; + const fields = this.columns + .filter(col => number_fields.includes(col.fieldtype)) + .map(col => col.field); + + // reset numeric fields + let updated_totals = Object.assign({}, this.dataView.getItem(last_index)); + fields.map(field => { + updated_totals[field] = 0.0; + }); + + // loop all the rows except the last Total row + for (let i = 0; i < data_length - 1; i++) { + const item = this.dataView.getItem(i); + fields.map(field => { + updated_totals[field] += item[field]; + }); + } + this.dataView.updateItem(updated_totals.id, updated_totals); + }, inline_filter: function (item) { var me = frappe.container.page.query_report; + if(me.report_doc.add_total_row) { + // always show totals row + if(Object.values(item).includes("'Total'")) return true; + } for (var columnId in me.columnFilters) { if (columnId !== undefined && me.columnFilters[columnId] !== "") { var c = me.grid.getColumns()[me.grid.getColumnIndex(columnId)]; @@ -774,6 +805,16 @@ frappe.views.QueryReport = Class.extend({ var cols = args.sortCols; me.data.sort(function (dataRow1, dataRow2) { + // Totals row should always be last + if(me.report_doc.add_total_row) { + if(Object.values(dataRow1).includes("'Total'")) { + return 1; + } + if(Object.values(dataRow2).includes("'Total'")) { + return -1; + } + } + for (var i = 0, l = cols.length; i < l; i++) { var field = cols[i].sortCol.field; var sign = cols[i].sortAsc ? 1 : -1; From 06a9b2de5b6e5c49aaf125580e538e1b72d7573f Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 10 Aug 2017 18:06:47 +0530 Subject: [PATCH 15/69] fix codacy --- frappe/public/js/frappe/views/reports/query_report.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 03ccd03ecc..9634ce57c9 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -594,7 +594,7 @@ frappe.views.QueryReport = Class.extend({ var me = this; this.dataView.onRowCountChanged.subscribe(function (e, args) { - me.update_totals_row(e, args); + me.update_totals_row(); me.grid.updateRowCount(); me.grid.render(); }); @@ -604,7 +604,7 @@ frappe.views.QueryReport = Class.extend({ me.grid.render(); }); }, - update_totals_row: function(e, args) { + update_totals_row: function() { if(!this.report_doc.add_total_row) return; const data_length = this.dataView.getLength(); From b51ad328afeb65f6e12d52e607db53ae2f3386e5 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Mon, 7 Aug 2017 23:17:59 +0530 Subject: [PATCH 16/69] Convert dict.keys() to list --- frappe/utils/bench_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/bench_helper.py b/frappe/utils/bench_helper.py index c4bb11d424..795deda05a 100644 --- a/frappe/utils/bench_helper.py +++ b/frappe/utils/bench_helper.py @@ -74,7 +74,7 @@ def get_app_commands(app): @click.command('get-frappe-commands') def get_frappe_commands(): - commands = get_app_commands('frappe').keys() + commands = list(get_app_commands('frappe').keys()) for app in get_apps(): app_commands = get_app_commands(app) From 6f7be6305405c7535f38afd70f002ea631cc7e22 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Mon, 7 Aug 2017 23:26:35 +0530 Subject: [PATCH 17/69] Encode 'site' before passing to hashlib.sha1 --- frappe/commands/site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/commands/site.py b/frappe/commands/site.py index 3716a0b0bd..6dc8c13311 100755 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -36,7 +36,7 @@ def _new_site(db_name, site, mariadb_root_username=None, mariadb_root_password=N """Install a new Frappe site""" if not db_name: - db_name = hashlib.sha1(site).hexdigest()[:16] + db_name = hashlib.sha1(site.encode()).hexdigest()[:16] from frappe.installer import install_db, make_site_dirs from frappe.installer import install_app as _install_app From 73a34c2234ac65b81f89f47fb3becc1922e697e7 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Mon, 7 Aug 2017 23:44:37 +0530 Subject: [PATCH 18/69] Use absolute import to import frappe.utils.background_jobs --- frappe/utils/scheduler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/scheduler.py b/frappe/utils/scheduler.py index 211bef028c..7fe78973d6 100755 --- a/frappe/utils/scheduler.py +++ b/frappe/utils/scheduler.py @@ -18,7 +18,7 @@ import MySQLdb import frappe.utils from frappe.utils import get_sites from datetime import datetime -from background_jobs import enqueue, get_jobs, queue_timeout +from frappe.utils.background_jobs import enqueue, get_jobs, queue_timeout from frappe.limits import has_expired from frappe.utils.data import get_datetime, now_datetime from frappe.core.doctype.user.user import STANDARD_USERS From 5313c2b2fe693be23b568cae1aa401193e131cbd Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Mon, 7 Aug 2017 23:58:41 +0530 Subject: [PATCH 19/69] Use string.ascii_letters instead of string.letters --- frappe/utils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py index 5435e4f279..2c5b21b812 100644 --- a/frappe/utils/__init__.py +++ b/frappe/utils/__init__.py @@ -126,7 +126,7 @@ def random_string(length): """generate a random string""" import string from random import choice - return ''.join([choice(string.letters + string.digits) for i in range(length)]) + return ''.join([choice(string.ascii_letters + string.digits) for i in range(length)]) def has_gravatar(email): From 127accb54a9c2c7e0e0ff167f39c8f436dd3ca5b Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 10:50:20 +0530 Subject: [PATCH 20/69] Use abslute imports in frappe/__init__.py --- frappe/__init__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index a4c721c8ab..13c09a069e 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -164,7 +164,7 @@ def connect(site=None, db_name=None): :param site: If site is given, calls `frappe.init`. :param db_name: Optional. Will use from `site_config.json`.""" - from database import Database + from frappe.database import Database if site: init(site) local.db = Database(user=db_name or local.conf.db_name) @@ -235,8 +235,8 @@ def cache(): def get_traceback(): """Returns error traceback.""" - import utils - return utils.get_traceback() + from frappe.utils import get_traceback + return get_traceback() def errprint(msg): """Log error. This is sent back as `exc` in response. @@ -268,7 +268,7 @@ def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None, :param raise_exception: [optional] Raise given exception and show message. :param as_table: [optional] If `msg` is a list of lists, render as HTML table. """ - from utils import encode + from frappe.utils import encode out = _dict(message=msg) @@ -421,8 +421,8 @@ def sendmail(recipients=[], sender="", subject="No Subject", message="No Message if not delayed: now = True - import email.queue - email.queue.send(recipients=recipients, sender=sender, + from frappe.email import queue + queue.send(recipients=recipients, sender=sender, subject=subject, message=message, text_content=text_content, reference_doctype = doctype or reference_doctype, reference_name = name or reference_name, unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, unsubscribe_message=unsubscribe_message, @@ -488,7 +488,7 @@ def clear_cache(user=None, doctype=None): elif user: frappe.sessions.clear_cache(user) else: # everything - import translate + from frappe import translate frappe.sessions.clear_cache() translate.clear_cache() reset_metadata_version() From f2742b5eac413f73264d89051fe47f8cc65f256b Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 11:03:06 +0530 Subject: [PATCH 21/69] Encode string before passing to hashlib.sha224 --- frappe/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index a4c721c8ab..c3d5d1aacd 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -576,7 +576,7 @@ def generate_hash(txt=None, length=None): """Generates random hash for given text + current timestamp + random string.""" import hashlib, time from .utils import random_string - digest = hashlib.sha224((txt or "") + repr(time.time()) + repr(random_string(8))).hexdigest() + digest = hashlib.sha224(((txt or "") + repr(time.time()) + repr(random_string(8))).encode()).hexdigest() if length: digest = digest[:length] return digest From 769338f136ccbafc23bd1e948c0b311423b428f3 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 11:43:23 +0530 Subject: [PATCH 22/69] Replaced all instances of basestring with six.string_types --- frappe/__init__.py | 8 ++++---- frappe/client.py | 14 +++++++------- frappe/contacts/doctype/address/address.py | 4 ++-- frappe/core/doctype/communication/email.py | 9 +++++---- frappe/core/doctype/communication/feed.py | 3 ++- frappe/core/doctype/file/file.py | 4 ++-- .../core/doctype/sms_settings/sms_settings.py | 3 ++- frappe/core/page/data_import_tool/exporter.py | 3 ++- frappe/core/page/data_import_tool/importer.py | 4 ++-- frappe/database.py | 14 +++++++------- .../desk/doctype/desktop_icon/desktop_icon.py | 6 +++--- frappe/desk/doctype/event/event.py | 3 ++- frappe/desk/form/linked_with.py | 3 ++- frappe/desk/form/run_method.py | 4 ++-- frappe/desk/form/utils.py | 3 ++- frappe/desk/page/setup_wizard/setup_wizard.py | 7 ++++--- frappe/desk/query_report.py | 19 ++++++++++--------- frappe/desk/reportview.py | 16 ++++++++-------- frappe/desk/search.py | 3 ++- .../email/doctype/email_alert/email_alert.py | 3 ++- .../doctype/standard_reply/standard_reply.py | 3 ++- frappe/email/email_body.py | 6 +++--- frappe/email/queue.py | 8 ++++---- frappe/frappeclient.py | 4 ++-- frappe/handler.py | 3 ++- frappe/integrations/utils.py | 3 ++- frappe/limits.py | 3 ++- frappe/model/base_document.py | 8 ++++---- frappe/model/db_query.py | 18 +++++++++--------- frappe/model/delete_doc.py | 3 ++- frappe/model/document.py | 6 +++--- frappe/model/mapper.py | 3 ++- frappe/model/naming.py | 5 +++-- frappe/model/utils/user_settings.py | 4 ++-- frappe/patches/v5_0/bookmarks_to_stars.py | 3 ++- frappe/permissions.py | 5 +++-- .../pages/integrations/razorpay_checkout.py | 3 ++- frappe/tests/test_permissions.py | 3 ++- frappe/translate.py | 6 +++--- frappe/twofactor.py | 5 +++-- frappe/utils/__init__.py | 8 ++++---- frappe/utils/background_jobs.py | 5 +++-- frappe/utils/csvutils.py | 4 ++-- frappe/utils/data.py | 12 ++++++------ frappe/utils/dateutils.py | 3 ++- frappe/utils/formatters.py | 3 ++- frappe/utils/html_utils.py | 3 ++- frappe/utils/make_random.py | 3 ++- frappe/utils/oauth.py | 5 +++-- frappe/utils/scheduler.py | 3 ++- frappe/utils/verified_command.py | 3 ++- frappe/utils/xlsxutils.py | 4 ++-- frappe/www/printview.py | 11 ++++++----- 53 files changed, 167 insertions(+), 135 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index a4c721c8ab..ff66967abe 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -6,7 +6,7 @@ globals attached to frappe module """ from __future__ import unicode_literals, print_function -from six import iteritems, text_type +from six import iteritems, text_type, string_types from werkzeug.local import Local, release_local import os, sys, importlib, inspect, json @@ -61,7 +61,7 @@ def as_unicode(text, encoding='utf-8'): return text elif text==None: return '' - elif isinstance(text, basestring): + elif isinstance(text, string_types): return text_type(text, encoding) else: return text_type(text) @@ -533,7 +533,7 @@ def has_website_permission(doc=None, ptype='read', user=None, verbose=False, doc user = session.user if doc: - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = get_doc(doctype, doc) doctype = doc.doctype @@ -903,7 +903,7 @@ def get_attr(method_string): def call(fn, *args, **kwargs): """Call a function and match arguments.""" - if isinstance(fn, basestring): + if isinstance(fn, string_types): fn = get_attr(fn) if hasattr(fn, 'fnargs'): diff --git a/frappe/client.py b/frappe/client.py index fafa535e0e..f257f6abbe 100644 --- a/frappe/client.py +++ b/frappe/client.py @@ -8,7 +8,7 @@ import frappe.model import frappe.utils import json, os -from six import iteritems +from six import iteritems, string_types ''' Handle RESTful requests that are mapped to the `/api/resource` route. @@ -92,7 +92,7 @@ def set_value(doctype, name, fieldname, value=None): if not value: values = fieldname - if isinstance(fieldname, basestring): + if isinstance(fieldname, string_types): try: values = json.loads(fieldname) except ValueError: @@ -118,7 +118,7 @@ def insert(doc=None): '''Insert a document :param doc: JSON or dict object to be inserted''' - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = json.loads(doc) if doc.get("parent") and doc.get("parenttype"): @@ -136,7 +136,7 @@ def insert_many(docs=None): '''Insert multiple documents :param docs: JSON or list of dict objects to be inserted in one request''' - if isinstance(docs, basestring): + if isinstance(docs, string_types): docs = json.loads(docs) out = [] @@ -162,7 +162,7 @@ def save(doc): '''Update (save) an existing document :param doc: JSON or dict object with the properties of the document to be updated''' - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = json.loads(doc) doc = frappe.get_doc(doc).save() @@ -183,7 +183,7 @@ def submit(doc): '''Submit a document :param doc: JSON or dict object to be submitted remotely''' - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = json.loads(doc) doc = frappe.get_doc(doc) @@ -221,7 +221,7 @@ def make_width_property_setter(doc): '''Set width Property Setter :param doc: Property Setter document with `width` property''' - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = json.loads(doc) if doc["doctype"]=="Property Setter" and doc["property"]=="width": frappe.get_doc(doc).insert(ignore_permissions = True) diff --git a/frappe/contacts/doctype/address/address.py b/frappe/contacts/doctype/address/address.py index 33a01f3192..18e51f3a61 100644 --- a/frappe/contacts/doctype/address/address.py +++ b/frappe/contacts/doctype/address/address.py @@ -13,7 +13,7 @@ from jinja2 import TemplateSyntaxError from frappe.utils.user import is_website_user from frappe.model.naming import make_autoname from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_links -from six import iteritems +from six import iteritems, string_types class Address(Document): @@ -115,7 +115,7 @@ def get_territory_from_address(address): if not address: return - if isinstance(address, basestring): + if isinstance(address, string_types): address = frappe.get_doc("Address", address) territory = None diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index 3af3def992..cbc9c5a9bb 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals, absolute_import from six.moves import range +from six import string_types import frappe import json from email.utils import formataddr @@ -71,7 +72,7 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received = # if no reference given, then send it against the communication comm.db_set(dict(reference_doctype='Communication', reference_name=comm.name)) - if isinstance(attachments, basestring): + if isinstance(attachments, string_types): attachments = json.loads(attachments) # if not committed, delayed task doesn't find the communication @@ -250,11 +251,11 @@ def prepare_to_notify(doc, print_html=None, print_format=None, attachments=None) print_format=print_format, html=print_html)) if attachments: - if isinstance(attachments, basestring): + if isinstance(attachments, string_types): attachments = json.loads(attachments) for a in attachments: - if isinstance(a, basestring): + if isinstance(a, string_types): # is it a filename? try: file = get_file(a) @@ -342,7 +343,7 @@ def add_attachments(name, attachments): # loop through attachments for a in attachments: - if isinstance(a, basestring): + if isinstance(a, string_types): attach = frappe.db.get_value("File", {"name":a}, ["file_name", "file_url", "is_private"], as_dict=1) diff --git a/frappe/core/doctype/communication/feed.py b/frappe/core/doctype/communication/feed.py index 2d939447cd..40d4418c5f 100644 --- a/frappe/core/doctype/communication/feed.py +++ b/frappe/core/doctype/communication/feed.py @@ -9,6 +9,7 @@ from frappe.utils import get_fullname from frappe import _ from frappe.core.doctype.communication.comment import add_info_comment from frappe.core.doctype.authentication_log.authentication_log import add_authentication_log +from six import string_types def update_feed(doc, method=None): "adds a new communication with comment_type='Updated'" @@ -25,7 +26,7 @@ def update_feed(doc, method=None): feed = doc.get_feed() if feed: - if isinstance(feed, basestring): + if isinstance(feed, string_types): feed = {"subject": feed} feed = frappe._dict(feed) diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index f9b65e6556..4be9693125 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -21,7 +21,7 @@ from frappe import _ from frappe.utils.nestedset import NestedSet from frappe.utils import strip, get_files_path from PIL import Image, ImageOps -from six import StringIO +from six import StringIO, string_types from six.moves.urllib.parse import unquote import zipfile @@ -305,7 +305,7 @@ def create_new_folder(file_name, folder): @frappe.whitelist() def move_file(file_list, new_parent, old_parent): - if isinstance(file_list, basestring): + if isinstance(file_list, string_types): file_list = json.loads(file_list) for file_obj in file_list: diff --git a/frappe/core/doctype/sms_settings/sms_settings.py b/frappe/core/doctype/sms_settings/sms_settings.py index a8b59beffa..70f5feebbc 100644 --- a/frappe/core/doctype/sms_settings/sms_settings.py +++ b/frappe/core/doctype/sms_settings/sms_settings.py @@ -9,6 +9,7 @@ from frappe import _, throw, msgprint from frappe.utils import nowdate from frappe.model.document import Document +from six import string_types class SMSSettings(Document): pass @@ -55,7 +56,7 @@ def get_contact_number(contact_name, ref_doctype, ref_name): def send_sms(receiver_list, msg, sender_name = '', success_msg = True): import json - if isinstance(receiver_list, basestring): + if isinstance(receiver_list, string_types): receiver_list = json.loads(receiver_list) if not isinstance(receiver_list, list): receiver_list = [receiver_list] diff --git a/frappe/core/page/data_import_tool/exporter.py b/frappe/core/page/data_import_tool/exporter.py index caa6ae90ef..4f7bf8a067 100644 --- a/frappe/core/page/data_import_tool/exporter.py +++ b/frappe/core/page/data_import_tool/exporter.py @@ -10,6 +10,7 @@ import re, csv, os from frappe.utils.csvutils import UnicodeWriter from frappe.utils import cstr, formatdate, format_datetime from frappe.core.page.data_import_tool.data_import_tool import get_data_keys +from six import string_types reflags = { "I":re.I, @@ -29,7 +30,7 @@ def get_template(doctype=None, parent_doctype=None, all_doctypes="No", with_data select_columns = json.loads(select_columns); docs_to_export = {} if doctype: - if isinstance(doctype, basestring): + if isinstance(doctype, string_types): doctype = [doctype]; if len(doctype) > 1: docs_to_export = doctype[1] diff --git a/frappe/core/page/data_import_tool/importer.py b/frappe/core/page/data_import_tool/importer.py index 308cef8f55..ae30757c34 100644 --- a/frappe/core/page/data_import_tool/importer.py +++ b/frappe/core/page/data_import_tool/importer.py @@ -17,7 +17,7 @@ from frappe.utils.file_manager import save_url from frappe.utils import cint, cstr, flt, getdate, get_datetime, get_url from frappe.core.page.data_import_tool.data_import_tool import get_data_keys -from six import text_type +from six import text_type, string_types @frappe.whitelist() def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, no_email=True, overwrite=None, @@ -119,7 +119,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, elif fieldtype in ("Float", "Currency", "Percent"): d[fieldname] = flt(d[fieldname]) elif fieldtype == "Date": - if d[fieldname] and isinstance(d[fieldname], basestring): + if d[fieldname] and isinstance(d[fieldname], string_types): d[fieldname] = getdate(parse_date(d[fieldname])) elif fieldtype == "Datetime": if d[fieldname]: diff --git a/frappe/database.py b/frappe/database.py index b702a8c53d..34a70699d1 100644 --- a/frappe/database.py +++ b/frappe/database.py @@ -18,7 +18,7 @@ import redis import frappe.model.meta from frappe.utils import now, get_datetime, cstr from frappe import _ -from six import text_type, binary_type +from six import text_type, binary_type, string_types from frappe.utils.global_search import sync_global_search from frappe.model.utils.link_count import flush_local_link_count from six import iteritems, text_type @@ -386,7 +386,7 @@ class Database: conditions.append(condition) - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = { "name": filters } for f in filters: @@ -451,7 +451,7 @@ class Database: user = frappe.db.get_values("User", "test@example.com", "*")[0] """ out = None - if cache and isinstance(filters, basestring) and \ + if cache and isinstance(filters, string_types) and \ (doctype, filters, fieldname) in self.value_cache: return self.value_cache[(doctype, filters, fieldname)] @@ -463,7 +463,7 @@ class Database: else: fields = fieldname if fieldname!="*": - if isinstance(fieldname, basestring): + if isinstance(fieldname, string_types): fields = [fieldname] else: fields = fieldname @@ -483,7 +483,7 @@ class Database: else: out = self.get_values_from_single(fields, filters, doctype, as_dict, debug, update) - if cache and isinstance(filters, basestring): + if cache and isinstance(filters, string_types): self.value_cache[(doctype, filters, fieldname)] = out return out @@ -789,7 +789,7 @@ class Database: :param dt: DocType name. :param dn: Document name or filter dict.""" - if isinstance(dt, basestring): + if isinstance(dt, string_types): if dt!="DocType" and dt==dn: return True # single always exists (!) try: @@ -854,7 +854,7 @@ class Database: add index `%s`(%s)""" % (doctype, index_name, ", ".join(fields))) def add_unique(self, doctype, fields, constraint_name=None): - if isinstance(fields, basestring): + if isinstance(fields, string_types): fields = [fields] if not constraint_name: constraint_name = "unique_" + "_".join(fields) diff --git a/frappe/desk/doctype/desktop_icon/desktop_icon.py b/frappe/desk/doctype/desktop_icon/desktop_icon.py index d4b4d2c1f5..1319ffba49 100644 --- a/frappe/desk/doctype/desktop_icon/desktop_icon.py +++ b/frappe/desk/doctype/desktop_icon/desktop_icon.py @@ -9,7 +9,7 @@ from frappe import _ import json import random from frappe.model.document import Document -from six import iteritems +from six import iteritems, string_types class DesktopIcon(Document): @@ -171,7 +171,7 @@ def add_user_icon(_doctype, _report=None, label=None, link=None, type='link', st @frappe.whitelist() def set_order(new_order, user=None): '''set new order by duplicating user icons (if user is set) or set global order''' - if isinstance(new_order, basestring): + if isinstance(new_order, string_types): new_order = json.loads(new_order) for i, module_name in enumerate(new_order): if module_name not in ('Explore',): @@ -228,7 +228,7 @@ def set_hidden_list(hidden_list, user=None): '''Sets property `hidden`=1 in **Desktop Icon** for given user. If user is None then it will set global values. It will also set the rest of the icons as shown (`hidden` = 0)''' - if isinstance(hidden_list, basestring): + if isinstance(hidden_list, string_types): hidden_list = json.loads(hidden_list) # set as hidden diff --git a/frappe/desk/doctype/event/event.py b/frappe/desk/doctype/event/event.py index b77b708ae6..0e97d78fb7 100644 --- a/frappe/desk/doctype/event/event.py +++ b/frappe/desk/doctype/event/event.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from six.moves import range +from six import string_types import frappe import json @@ -69,7 +70,7 @@ def send_event_digest(): def get_events(start, end, user=None, for_reminder=False, filters=None): if not user: user = frappe.session.user - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = json.loads(filters) roles = frappe.get_roles(user) events = frappe.db.sql("""select name, subject, description, color, diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index 3a3e1d5a6b..e5192b1edb 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -7,10 +7,11 @@ from frappe.model.meta import is_single from frappe.modules import load_doctype_module import frappe.desk.form.meta import frappe.desk.form.load +from six import string_types @frappe.whitelist() def get_linked_docs(doctype, name, linkinfo=None, for_doctype=None): - if isinstance(linkinfo, basestring): + if isinstance(linkinfo, string_types): # additional fields are added in linkinfo linkinfo = json.loads(linkinfo) diff --git a/frappe/desk/form/run_method.py b/frappe/desk/form/run_method.py index 1253cc49b3..0a973c35ed 100644 --- a/frappe/desk/form/run_method.py +++ b/frappe/desk/form/run_method.py @@ -6,7 +6,7 @@ import json, inspect import frappe from frappe import _ from frappe.utils import cint -from six import text_type +from six import text_type, string_types @frappe.whitelist() def runserverobj(method, docs=None, dt=None, dn=None, arg=None, args=None): @@ -62,7 +62,7 @@ def make_csv_output(res, dt): for r in res: row = [] for v in r: - if isinstance(v, basestring): + if isinstance(v, string_types): v = v.encode("utf-8") row.append(v) writer.writerow(row) diff --git a/frappe/desk/form/utils.py b/frappe/desk/form/utils.py index cdb138b325..999a83a2fe 100644 --- a/frappe/desk/form/utils.py +++ b/frappe/desk/form/utils.py @@ -7,6 +7,7 @@ import frappe.desk.form.meta import frappe.desk.form.load from frappe import _ +from six import string_types @frappe.whitelist() def remove_attach(): @@ -65,7 +66,7 @@ def get_next(doctype, value, prev, filters=None, order_by="modified desc"): sort_field, sort_order = order_by.split(" ") if not filters: filters = [] - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = json.loads(filters) # condition based on sort order diff --git a/frappe/desk/page/setup_wizard/setup_wizard.py b/frappe/desk/page/setup_wizard/setup_wizard.py index ad3108b67a..e0d8f721b4 100755 --- a/frappe/desk/page/setup_wizard/setup_wizard.py +++ b/frappe/desk/page/setup_wizard/setup_wizard.py @@ -11,6 +11,7 @@ from frappe.utils.file_manager import save_file from frappe.utils.password import update_password from werkzeug.useragents import UserAgent import install_fixtures +from six import string_types @frappe.whitelist() def setup_complete(args): @@ -127,14 +128,14 @@ def update_user_name(args): def process_args(args): if not args: args = frappe.local.form_dict - if isinstance(args, basestring): + if isinstance(args, string_types): args = json.loads(args) args = frappe._dict(args) # strip the whitespace for key, value in args.items(): - if isinstance(value, basestring): + if isinstance(value, string_types): args[key] = strip(value) return args @@ -204,7 +205,7 @@ def load_user_details(): def prettify_args(args): # remove attachments for key, val in args.items(): - if isinstance(val, basestring) and "data:image" in val: + if isinstance(val, string_types) and "data:image" in val: filename = val.split("data:image", 1)[0].strip(", ") size = round((len(val) * 3 / 4) / 1048576.0, 2) args[key] = "Image Attached: '{0}' of size {1} MB".format(filename, size) diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py index 073576c437..d2b7591574 100644 --- a/frappe/desk/query_report.py +++ b/frappe/desk/query_report.py @@ -13,6 +13,7 @@ from frappe.model.utils import render_include from frappe.translate import send_translations import frappe.desk.reportview from frappe.permissions import get_role_permissions +from six import string_types def get_report_doc(report_name): doc = frappe.get_doc("Report", report_name) @@ -70,7 +71,7 @@ def run(report_name, filters=None, user=None): if not filters: filters = [] - if filters and isinstance(filters, basestring): + if filters and isinstance(filters, string_types): filters = json.loads(filters) if not frappe.has_permission(report.ref_doctype, "report"): @@ -127,13 +128,13 @@ def export_query(): if "csrf_token" in data: del data["csrf_token"] - if isinstance(data.get("filters"), basestring): + if isinstance(data.get("filters"), string_types): filters = json.loads(data["filters"]) - if isinstance(data.get("report_name"), basestring): + if isinstance(data.get("report_name"), string_types): report_name = data["report_name"] - if isinstance(data.get("file_format_type"), basestring): + if isinstance(data.get("file_format_type"), string_types): file_format_type = data["file_format_type"] - if isinstance(data.get("visible_idx"), basestring): + if isinstance(data.get("visible_idx"), string_types): visible_idx = json.loads(data.get("visible_idx")) else: visible_idx = None @@ -181,7 +182,7 @@ def add_total_row(result, columns, meta = None): has_percent = [] for i, col in enumerate(columns): fieldtype, options = None, None - if isinstance(col, basestring): + if isinstance(col, string_types): if meta: # get fieldtype from the meta field = meta.get_field(col) @@ -214,7 +215,7 @@ def add_total_row(result, columns, meta = None): total_row[i] = flt(total_row[i]) / len(result) first_col_fieldtype = None - if isinstance(columns[0], basestring): + if isinstance(columns[0], string_types): first_col = columns[0].split(":") if len(first_col) > 1: first_col_fieldtype = first_col[1].split("/")[0] @@ -319,7 +320,7 @@ def get_linked_doctypes(columns, data): for idx, col in enumerate(columns): df = columns_dict[idx] if df.get("fieldtype")=="Link": - if isinstance(col, basestring): + if isinstance(col, string_types): linked_doctypes[df["options"]] = idx else: # dict @@ -355,7 +356,7 @@ def get_columns_dict(columns): col_dict = frappe._dict() # string - if isinstance(col, basestring): + if isinstance(col, string_types): col = col.split(":") if len(col) > 1: if "/" in col[1]: diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py index 0ce1d495f8..9474f6b7e8 100644 --- a/frappe/desk/reportview.py +++ b/frappe/desk/reportview.py @@ -10,7 +10,7 @@ import frappe.permissions import MySQLdb from frappe.model.db_query import DatabaseQuery from frappe import _ -from six import text_type +from six import text_type, string_types @frappe.whitelist() def get(): @@ -31,13 +31,13 @@ def get_form_params(): if "csrf_token" in data: del data["csrf_token"] - if isinstance(data.get("filters"), basestring): + if isinstance(data.get("filters"), string_types): data["filters"] = json.loads(data["filters"]) - if isinstance(data.get("fields"), basestring): + if isinstance(data.get("fields"), string_types): data["fields"] = json.loads(data["fields"]) - if isinstance(data.get("docstatus"), basestring): + if isinstance(data.get("docstatus"), string_types): data["docstatus"] = json.loads(data["docstatus"]) - if isinstance(data.get("save_user_settings"), basestring): + if isinstance(data.get("save_user_settings"), string_types): data["save_user_settings"] = json.loads(data["save_user_settings"]) else: data["save_user_settings"] = True @@ -341,7 +341,7 @@ def build_match_conditions(doctype, as_condition=True): return match_conditions def get_filters_cond(doctype, filters, conditions, ignore_permissions=None, with_match_conditions=False): - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = json.loads(filters) if filters: @@ -350,10 +350,10 @@ def get_filters_cond(doctype, filters, conditions, ignore_permissions=None, with filters = filters.items() flt = [] for f in filters: - if isinstance(f[1], basestring) and f[1][0] == '!': + if isinstance(f[1], string_types) and f[1][0] == '!': flt.append([doctype, f[0], '!=', f[1][1:]]) else: - value = frappe.db.escape(f[1]) if isinstance(f[1], basestring) else f[1] + value = frappe.db.escape(f[1]) if isinstance(f[1], string_types) else f[1] flt.append([doctype, f[0], '=', value]) query = DatabaseQuery(doctype) diff --git a/frappe/desk/search.py b/frappe/desk/search.py index d9f881e3db..e9c5c62bd5 100644 --- a/frappe/desk/search.py +++ b/frappe/desk/search.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import frappe, json from frappe.utils import cstr, unique from frappe import _ +from six import string_types # this is called by the Link Field @frappe.whitelist() @@ -18,7 +19,7 @@ def search_link(doctype, txt, query=None, filters=None, page_length=20, searchfi @frappe.whitelist() def search_widget(doctype, txt, query=None, searchfield=None, start=0, page_length=10, filters=None, filter_fields=None, as_dict=False): - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = json.loads(filters) meta = frappe.get_meta(doctype) diff --git a/frappe/email/doctype/email_alert/email_alert.py b/frappe/email/doctype/email_alert/email_alert.py index f4bce6f5cd..8ef2423299 100755 --- a/frappe/email/doctype/email_alert/email_alert.py +++ b/frappe/email/doctype/email_alert/email_alert.py @@ -12,6 +12,7 @@ from frappe.utils.data import parse_val from frappe.utils.jinja import validate_template from frappe.modules.utils import export_module_json, get_doc_module from markdown2 import markdown +from six import string_types class EmailAlert(Document): def autoname(self): @@ -210,7 +211,7 @@ def trigger_email_alerts(doc, method=None): def evaluate_alert(doc, alert, event): from jinja2 import TemplateError try: - if isinstance(alert, basestring): + if isinstance(alert, string_types): alert = frappe.get_doc("Email Alert", alert) context = get_context(doc) diff --git a/frappe/email/doctype/standard_reply/standard_reply.py b/frappe/email/doctype/standard_reply/standard_reply.py index 5ca40005a2..17828cb352 100755 --- a/frappe/email/doctype/standard_reply/standard_reply.py +++ b/frappe/email/doctype/standard_reply/standard_reply.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe, json from frappe.model.document import Document from frappe.utils.jinja import validate_template +from six import string_types class StandardReply(Document): def validate(self): @@ -13,7 +14,7 @@ class StandardReply(Document): @frappe.whitelist() def get_standard_reply(template_name, doc): '''Returns the processed HTML of a standard reply with the given doc''' - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = json.loads(doc) standard_reply = frappe.get_doc("Standard Reply", template_name) diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index 12deec3427..b589986bc0 100755 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -8,7 +8,7 @@ from frappe.email.smtp import get_outgoing_email_account from frappe.utils import (get_url, scrub_urls, strip, expand_relative_urls, cint, split_emails, to_markdown, markdown, encode, random_string, parse_addr) import email.utils -from six import iteritems, text_type +from six import iteritems, text_type, string_types from email.mime.multipart import MIMEMultipart @@ -54,7 +54,7 @@ class EMail: from email import Charset Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8') - if isinstance(recipients, basestring): + if isinstance(recipients, string_types): recipients = recipients.replace(';', ',').replace('\n', '') recipients = split_emails(recipients) @@ -432,7 +432,7 @@ def get_header(header=None): if not header: return None - if isinstance(header, basestring): + if isinstance(header, string_types): # header = 'My Title' header = [header, None] if len(header) == 1: diff --git a/frappe/email/queue.py b/frappe/email/queue.py index e3e2267f6e..975e36f23f 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -15,7 +15,7 @@ from frappe.utils import get_url, nowdate, encode, now_datetime, add_days, split from frappe.utils.file_manager import get_file from rq.timeouts import JobTimeoutException from frappe.utils.scheduler import log -from six import text_type +from six import text_type, string_types class EmailLimitCrossedError(frappe.ValidationError): pass @@ -55,10 +55,10 @@ def send(recipients=None, sender=None, subject=None, message=None, text_content= if not recipients and not cc: return - if isinstance(recipients, basestring): + if isinstance(recipients, string_types): recipients = split_emails(recipients) - if isinstance(cc, basestring): + if isinstance(cc, string_types): cc = split_emails(cc) if isinstance(send_after, int): @@ -471,7 +471,7 @@ def prepare_message(email, recipient, recipients_list): pass else: if email.expose_recipients == "footer": - if isinstance(email.show_as_cc, basestring): + if isinstance(email.show_as_cc, string_types): email.show_as_cc = email.show_as_cc.split(",") email_sent_to = [r.recipient for r in recipients_list] email_sent_cc = ", ".join([e for e in email_sent_to if e in email.show_as_cc]) diff --git a/frappe/frappeclient.py b/frappe/frappeclient.py index 30c71956dd..b92463f474 100644 --- a/frappe/frappeclient.py +++ b/frappe/frappeclient.py @@ -2,7 +2,7 @@ from __future__ import print_function import requests import json import frappe -from six import iteritems +from six import iteritems, string_types ''' FrappeClient is a library that helps you connect with other frappe systems @@ -49,7 +49,7 @@ class FrappeClient(object): def get_list(self, doctype, fields='"*"', filters=None, limit_start=0, limit_page_length=0): """Returns list of records of a particular type""" - if not isinstance(fields, basestring): + if not isinstance(fields, string_types): fields = json.dumps(fields) params = { "fields": fields, diff --git a/frappe/handler.py b/frappe/handler.py index 4845b4d725..98d88297fb 100755 --- a/frappe/handler.py +++ b/frappe/handler.py @@ -11,6 +11,7 @@ import frappe.utils.file_manager import frappe.desk.form.run_method from frappe.utils.response import build_response from werkzeug.wrappers import Response +from six import string_types def handle(): """handle request""" @@ -63,7 +64,7 @@ def is_whitelisted(method): # strictly sanitize form_dict # escapes html characters like <> except for predefined tags like a, b, ul etc. for key, value in frappe.form_dict.items(): - if isinstance(value, basestring): + if isinstance(value, string_types): frappe.form_dict[key] = frappe.utils.sanitize_html(value) else: diff --git a/frappe/integrations/utils.py b/frappe/integrations/utils.py index 8215eefd7b..c79a190e94 100644 --- a/frappe/integrations/utils.py +++ b/frappe/integrations/utils.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import frappe import json from six.moves.urllib.parse import parse_qs +from six import string_types from frappe.utils import get_request_session from frappe import _ @@ -49,7 +50,7 @@ def make_post_request(url, auth=None, headers=None, data=None): raise exc def create_request_log(data, integration_type, service_name, name=None): - if isinstance(data, basestring): + if isinstance(data, string_types): data = json.loads(data) integration_request = frappe.get_doc({ diff --git a/frappe/limits.py b/frappe/limits.py index 0f597e445f..d804aab54b 100755 --- a/frappe/limits.py +++ b/frappe/limits.py @@ -7,6 +7,7 @@ from frappe.utils.data import formatdate from frappe.utils.user import get_enabled_system_users, disable_users import os, subprocess, urllib from six.moves.urllib.parse import parse_qsl, urlsplit, urlunsplit +from six import string_types class SiteExpiredError(frappe.ValidationError): http_status_code = 417 @@ -162,7 +163,7 @@ def update_limits(limits_dict): def clear_limit(key): '''Remove a limit option from site_config''' limits = get_limits() - to_clear = [key] if isinstance(key, basestring) else key + to_clear = [key] if isinstance(key, string_types) else key for key in to_clear: if key in limits: del limits[key] diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 0151feac8e..0babe8ca53 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -2,7 +2,7 @@ # MIT License. See license.txt from __future__ import unicode_literals -from six import reraise as raise_, iteritems +from six import reraise as raise_, iteritems, string_types import frappe, sys from frappe import _ from frappe.utils import (cint, flt, now, cstr, strip_html, getdate, get_datetime, to_timedelta, @@ -610,7 +610,7 @@ class BaseDocument(object): return for fieldname, value in self.get_valid_dict().items(): - if not value or not isinstance(value, basestring): + if not value or not isinstance(value, string_types): continue value = frappe.as_unicode(value) @@ -673,7 +673,7 @@ class BaseDocument(object): :param parentfield: If fieldname is in child table.""" from frappe.model.meta import get_field_precision - if parentfield and not isinstance(parentfield, basestring): + if parentfield and not isinstance(parentfield, string_types): parentfield = parentfield.parentfield cache_key = parentfield or "main" @@ -831,7 +831,7 @@ def _filter(data, filters, limit=None): fval = ("not None", fval) elif fval is False: fval = ("None", fval) - elif isinstance(fval, basestring) and fval.startswith("^"): + elif isinstance(fval, string_types) and fval.startswith("^"): fval = ("^", fval[1:]) else: fval = ("=", fval) diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py index 205fd3a1e7..8dde636731 100644 --- a/frappe/model/db_query.py +++ b/frappe/model/db_query.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals -from six import iteritems +from six import iteritems, string_types """build query for doclistview and return results""" @@ -47,7 +47,7 @@ class DatabaseQuery(object): filters, fields = fields, filters elif fields and isinstance(filters, list) \ - and len(filters) > 1 and isinstance(filters[0], basestring): + and len(filters) > 1 and isinstance(filters[0], string_types): # if `filters` is a list of strings, its probably fields filters, fields = fields, filters @@ -157,7 +157,7 @@ class DatabaseQuery(object): def parse_args(self): """Convert fields and filters from strings to list, dicts""" - if isinstance(self.fields, basestring): + if isinstance(self.fields, string_types): if self.fields == "*": self.fields = ["*"] else: @@ -168,7 +168,7 @@ class DatabaseQuery(object): for filter_name in ["filters", "or_filters"]: filters = getattr(self, filter_name) - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = json.loads(filters) if isinstance(filters, dict): @@ -230,7 +230,7 @@ class DatabaseQuery(object): # remove from filters to_remove = [] for each in self.filters: - if isinstance(each, basestring): + if isinstance(each, string_types): each = [each] for element in each: @@ -264,7 +264,7 @@ class DatabaseQuery(object): filters = [filters] for f in filters: - if isinstance(f, basestring): + if isinstance(f, string_types): conditions.append(f) else: conditions.append(self.prepare_filter_condition(f)) @@ -331,12 +331,12 @@ class DatabaseQuery(object): value = get_time(f.value).strftime("%H:%M:%S.%f") fallback = "'00:00:00'" - elif f.operator.lower() in ("like", "not like") or (isinstance(f.value, basestring) and + elif f.operator.lower() in ("like", "not like") or (isinstance(f.value, string_types) and (not df or df.fieldtype not in ["Float", "Int", "Currency", "Percent", "Check"])): value = "" if f.value==None else f.value fallback = '""' - if f.operator.lower() in ("like", "not like") and isinstance(value, basestring): + if f.operator.lower() in ("like", "not like") and isinstance(value, string_types): # because "like" uses backslash (\) for escaping value = value.replace("\\", "\\\\").replace("%", "%%") @@ -345,7 +345,7 @@ class DatabaseQuery(object): fallback = 0 # put it inside double quotes - if isinstance(value, basestring) and not f.operator.lower() == 'between': + if isinstance(value, string_types) and not f.operator.lower() == 'between': value = '"{0}"'.format(frappe.db.escape(value, percent=False)) if (self.ignore_ifnull diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py index 3e4f60c7f6..03cfca6652 100644 --- a/frappe/model/delete_doc.py +++ b/frappe/model/delete_doc.py @@ -12,6 +12,7 @@ from frappe.utils.password import delete_all_passwords_for from frappe import _ from frappe.model.naming import revert_series_if_last from frappe.utils.global_search import delete_for_document +from six import string_types def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False, ignore_permissions=False, flags=None, ignore_on_trash=False): @@ -26,7 +27,7 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa name = frappe.form_dict.get('dn') names = name - if isinstance(name, basestring): + if isinstance(name, string_types): names = [name] for name in names or []: diff --git a/frappe/model/document.py b/frappe/model/document.py index 3e8db22802..2cab4c0b4c 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -9,7 +9,7 @@ from frappe.utils import flt, cstr, now, get_datetime_str, file_lock from frappe.utils.background_jobs import enqueue from frappe.model.base_document import BaseDocument, get_controller from frappe.model.naming import set_new_name -from six import iteritems +from six import iteritems, string_types from werkzeug.exceptions import NotFound, Forbidden import hashlib, json from frappe.model import optional_fields @@ -41,7 +41,7 @@ def get_doc(arg1, arg2=None): """ if isinstance(arg1, BaseDocument): return arg1 - elif isinstance(arg1, basestring): + elif isinstance(arg1, string_types): doctype = arg1 else: doctype = arg1.get("doctype") @@ -67,7 +67,7 @@ class Document(BaseDocument): self._default_new_docs = {} self.flags = frappe._dict() - if arg1 and isinstance(arg1, basestring): + if arg1 and isinstance(arg1, string_types): if not arg2: # single self.doctype = self.name = arg1 diff --git a/frappe/model/mapper.py b/frappe/model/mapper.py index 72a9a77e3c..8f77668204 100644 --- a/frappe/model/mapper.py +++ b/frappe/model/mapper.py @@ -6,6 +6,7 @@ import frappe, json from frappe import _ from frappe.utils import cstr from frappe.model import default_fields +from six import string_types @frappe.whitelist() def make_mapped_doc(method, source_name, selected_children=None): @@ -43,7 +44,7 @@ def get_mapped_doc(from_doctype, from_docname, table_maps, target_doc=None, # main if not target_doc: target_doc = frappe.new_doc(table_maps[from_doctype]["doctype"]) - elif isinstance(target_doc, basestring): + elif isinstance(target_doc, string_types): target_doc = frappe.get_doc(json.loads(target_doc)) if not ignore_permissions and not target_doc.has_permission("create"): diff --git a/frappe/model/naming.py b/frappe/model/naming.py index c47422c3ec..6ccc5a0a19 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -6,6 +6,7 @@ import frappe from frappe import _ from frappe.utils import now_datetime, cint import re +from six import string_types def set_new_name(doc): """ @@ -99,7 +100,7 @@ def make_autoname(key='', doctype='', doc=''): def parse_naming_series(parts, doctype= '', doc = ''): n = '' - if isinstance(parts, basestring): + if isinstance(parts, string_types): parts = parts.split('.') series_set = False @@ -123,7 +124,7 @@ def parse_naming_series(parts, doctype= '', doc = ''): part = doc.get(e) else: part = e - if isinstance(part, basestring): + if isinstance(part, string_types): n+=part return n diff --git a/frappe/model/utils/user_settings.py b/frappe/model/utils/user_settings.py index 1034334049..bbbd9298f7 100644 --- a/frappe/model/utils/user_settings.py +++ b/frappe/model/utils/user_settings.py @@ -2,7 +2,7 @@ # such as page_limit, filters, last_view import frappe, json -from six import iteritems +from six import iteritems, string_types def get_user_settings(doctype, for_update=False): @@ -27,7 +27,7 @@ def update_user_settings(doctype, user_settings, for_update=False): else: current = json.loads(get_user_settings(doctype, for_update = True)) - if isinstance(current, basestring): + if isinstance(current, string_types): # corrupt due to old code, remove this in a future release current = {} diff --git a/frappe/patches/v5_0/bookmarks_to_stars.py b/frappe/patches/v5_0/bookmarks_to_stars.py index 603697a1b7..048d059701 100644 --- a/frappe/patches/v5_0/bookmarks_to_stars.py +++ b/frappe/patches/v5_0/bookmarks_to_stars.py @@ -3,6 +3,7 @@ import json import frappe import frappe.defaults from frappe.desk.like import _toggle_like +from six import string_types def execute(): for user in frappe.get_all("User"): @@ -12,7 +13,7 @@ def execute(): if not bookmarks: continue - if isinstance(bookmarks, basestring): + if isinstance(bookmarks, string_types): bookmarks = json.loads(bookmarks) for opts in bookmarks: diff --git a/frappe/permissions.py b/frappe/permissions.py index 29f223d08e..2dc57253e9 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals, print_function from six.moves import range +from six import string_types import frappe, copy, json from frappe import _, msgprint from frappe.utils import cint @@ -51,7 +52,7 @@ def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None): ["read" if ptype in ("email", "print") else ptype]) if doc: - doc_name = doc if isinstance(doc, basestring) else doc.name + doc_name = doc if isinstance(doc, string_types) else doc.name if doc_name in shared: if verbose: print("Shared") if ptype in ("read", "write", "share") or meta.permissions[0].get(ptype): @@ -75,7 +76,7 @@ def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None): perm = True if doc: - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = frappe.get_doc(meta.name, doc) owner_perm = user_perm = controller_perm = None diff --git a/frappe/templates/pages/integrations/razorpay_checkout.py b/frappe/templates/pages/integrations/razorpay_checkout.py index d37fef21e6..3af552d6a6 100644 --- a/frappe/templates/pages/integrations/razorpay_checkout.py +++ b/frappe/templates/pages/integrations/razorpay_checkout.py @@ -5,6 +5,7 @@ import frappe from frappe import _ from frappe.utils import flt, cint import json +from six import string_types no_cache = 1 no_sitemap = 1 @@ -39,7 +40,7 @@ def get_api_key(): def make_payment(razorpay_payment_id, options, reference_doctype, reference_docname): data = {} - if isinstance(options, basestring): + if isinstance(options, string_types): data = json.loads(options) data.update({ diff --git a/frappe/tests/test_permissions.py b/frappe/tests/test_permissions.py index d54c484eba..fecae8c6aa 100644 --- a/frappe/tests/test_permissions.py +++ b/frappe/tests/test_permissions.py @@ -14,6 +14,7 @@ from frappe.permissions import (add_user_permission, remove_user_permission, get_valid_perms) from frappe.core.page.permission_manager.permission_manager import update, reset from frappe.test_runner import make_test_records_for_doctype +from six import string_types test_records = frappe.get_test_records('Blog Post') @@ -361,7 +362,7 @@ def set_user_permission_doctypes(doctypes, role, apply_user_permissions, user_permission_doctypes): user_permission_doctypes = None if not user_permission_doctypes else json.dumps(user_permission_doctypes) - if isinstance(doctypes, basestring): + if isinstance(doctypes, string_types): doctypes = [doctypes] for doctype in doctypes: diff --git a/frappe/translate.py b/frappe/translate.py index ea1c1891e8..ab5ff018a6 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals, print_function -from six import iteritems, text_type +from six import iteritems, text_type, string_types """ frappe.translate @@ -359,7 +359,7 @@ def get_messages_from_workflow(doctype=None, app_name=None): else: fixtures = frappe.get_hooks('fixtures', app_name=app_name) or [] for fixture in fixtures: - if isinstance(fixture, basestring) and fixture == 'Worflow': + if isinstance(fixture, string_types) and fixture == 'Worflow': workflows = frappe.get_all('Workflow') break elif isinstance(fixture, dict) and fixture.get('dt', fixture.get('doctype')) == 'Workflow': @@ -394,7 +394,7 @@ def get_messages_from_custom_fields(app_name): custom_fields = [] for fixture in fixtures: - if isinstance(fixture, basestring) and fixture == 'Custom Field': + if isinstance(fixture, string_types) and fixture == 'Custom Field': custom_fields = frappe.get_all('Custom Field', fields=['name','label', 'description', 'fieldtype', 'options']) break elif isinstance(fixture, dict) and fixture.get('dt', fixture.get('doctype')) == 'Custom Field': diff --git a/frappe/twofactor.py b/frappe/twofactor.py index bb796fd296..2e2562964a 100644 --- a/frappe/twofactor.py +++ b/frappe/twofactor.py @@ -12,6 +12,7 @@ from pyqrcode import create as qrcreate from StringIO import StringIO from base64 import b64encode, b32encode from frappe.utils import get_url, get_datetime, time_diff_in_seconds +from six import string_types class ExpiredLoginException(Exception): pass @@ -73,7 +74,7 @@ def cache_2fa_data(user, token, otp_secret, tmp_id): def two_factor_is_enabled_for_(user): '''Check if 2factor is enabled for user.''' - if isinstance(user, basestring): + if isinstance(user, string_types): user = frappe.get_doc('User', user) roles = [frappe.db.escape(d.role) for d in user.roles or []] @@ -357,7 +358,7 @@ def delete_all_barcodes_for_users(): def should_remove_barcode_image(barcode): '''Check if it's time to delete barcode image from server. ''' - if isinstance(barcode, basestring): + if isinstance(barcode, string_types): barcode = frappe.get_doc('File', barcode) lifespan = frappe.db.get_value('System Settings', 'System Settings', 'lifespan_qrcode_image') if time_diff_in_seconds(get_datetime(), barcode.creation) > int(lifespan): diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py index 5435e4f279..86f5ebac1d 100644 --- a/frappe/utils/__init__.py +++ b/frappe/utils/__init__.py @@ -14,7 +14,7 @@ from email.utils import parseaddr, formataddr # utility functions like cint, int, flt, etc. from frappe.utils.data import * from six.moves.urllib.parse import quote -from six import text_type +from six import text_type, string_types default_fields = ['doctype', 'name', 'owner', 'creation', 'modified', 'modified_by', 'parent', 'parentfield', 'parenttype', 'idx', 'docstatus'] @@ -63,7 +63,7 @@ def get_formatted_email(user): def extract_email_id(email): """fetch only the email part of the Email Address""" email_id = parse_addr(email)[1] - if email_id and isinstance(email_id, basestring) and not isinstance(email_id, text_type): + if email_id and isinstance(email_id, string_types) and not isinstance(email_id, text_type): email_id = email_id.decode("utf-8", "ignore") return email_id @@ -305,14 +305,14 @@ def get_request_site_address(full_address=False): def encode_dict(d, encoding="utf-8"): for key in d: - if isinstance(d[key], basestring) and isinstance(d[key], text_type): + if isinstance(d[key], string_types) and isinstance(d[key], text_type): d[key] = d[key].encode(encoding) return d def decode_dict(d, encoding="utf-8"): for key in d: - if isinstance(d[key], basestring) and not isinstance(d[key], text_type): + if isinstance(d[key], string_types) and not isinstance(d[key], text_type): d[key] = d[key].decode(encoding, "ignore") return d diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index e9c0bc8406..234ba3b929 100755 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -8,6 +8,7 @@ import frappe import MySQLdb import os, socket, time from frappe import _ +from six import string_types default_timeout = 300 queue_timeout = { @@ -60,7 +61,7 @@ def execute_job(site, method, event, job_name, kwargs, user=None, async=True, re if user: frappe.set_user(user) - if isinstance(method, basestring): + if isinstance(method, string_types): method_name = method method = frappe.get_attr(method) else: @@ -151,7 +152,7 @@ def get_queue_list(queue_list=None): '''Defines possible queues. Also wraps a given queue in a list after validating.''' default_queue_list = queue_timeout.keys() if queue_list: - if isinstance(queue_list, basestring): + if isinstance(queue_list, string_types): queue_list = [queue_list] for queue in queue_list: diff --git a/frappe/utils/csvutils.py b/frappe/utils/csvutils.py index 825a38c5d7..26394c28bb 100644 --- a/frappe/utils/csvutils.py +++ b/frappe/utils/csvutils.py @@ -6,7 +6,7 @@ import frappe from frappe import msgprint, _ import json import csv -from six import StringIO, text_type +from six import StringIO, text_type, string_types from frappe.utils import encode, cstr, cint, flt, comma_or def read_csv_content_from_uploaded_file(ignore_encoding=False): @@ -78,7 +78,7 @@ def read_csv_content(fcontent, ignore_encoding=False): @frappe.whitelist() def send_csv_to_client(args): - if isinstance(args, basestring): + if isinstance(args, string_types): args = json.loads(args) args = frappe._dict(args) diff --git a/frappe/utils/data.py b/frappe/utils/data.py index a07cb61957..94fad5ed0d 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -14,7 +14,7 @@ from num2words import num2words from six.moves import html_parser as HTMLParser from six.moves.urllib.parse import quote from html2text import html2text -from six import iteritems, text_type +from six import iteritems, text_type, string_types DATE_FORMAT = "%Y-%m-%d" TIME_FORMAT = "%H:%M:%S.%f" @@ -63,7 +63,7 @@ def get_datetime(datetime_str=None): return parser.parse(datetime_str) def to_timedelta(time_str): - if isinstance(time_str, basestring): + if isinstance(time_str, string_types): t = parser.parse(time_str) return datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second, microseconds=t.microsecond) @@ -80,7 +80,7 @@ def add_to_date(date, years=0, months=0, days=0, hours=0, as_string=False, as_da if hours: as_datetime = True - if isinstance(date, basestring): + if isinstance(date, string_types): as_string = True if " " in date: as_datetime = True @@ -196,7 +196,7 @@ def get_time(time_str): return parser.parse(time_str).time() def get_datetime_str(datetime_obj): - if isinstance(datetime_obj, basestring): + if isinstance(datetime_obj, string_types): datetime_obj = get_datetime(datetime_obj) return datetime_obj.strftime(DATETIME_FORMAT) @@ -261,7 +261,7 @@ def has_common(l1, l2): def flt(s, precision=None): """Convert to float (ignore commas)""" - if isinstance(s, basestring): + if isinstance(s, string_types): s = s.replace(',','') try: @@ -522,7 +522,7 @@ def pretty_date(iso_datetime): if not iso_datetime: return '' import math - if isinstance(iso_datetime, basestring): + if isinstance(iso_datetime, string_types): iso_datetime = datetime.datetime.strptime(iso_datetime, DATETIME_FORMAT) now_dt = datetime.datetime.strptime(now(), DATETIME_FORMAT) dt_diff = now_dt - iso_datetime diff --git a/frappe/utils/dateutils.py b/frappe/utils/dateutils.py index a9b5818efa..79722aa159 100644 --- a/frappe/utils/dateutils.py +++ b/frappe/utils/dateutils.py @@ -6,6 +6,7 @@ import frappe import frappe.defaults import datetime from frappe.utils import get_datetime +from six import string_types # global values -- used for caching dateformats = { @@ -68,7 +69,7 @@ def get_user_date_format(): def datetime_in_user_format(date_time): if not date_time: return "" - if isinstance(date_time, basestring): + if isinstance(date_time, string_types): date_time = get_datetime(date_time) from frappe.utils import formatdate return formatdate(date_time.date()) + " " + date_time.strftime("%H:%M") diff --git a/frappe/utils/formatters.py b/frappe/utils/formatters.py index bf5a81e4f7..4753fce060 100644 --- a/frappe/utils/formatters.py +++ b/frappe/utils/formatters.py @@ -7,11 +7,12 @@ import datetime from frappe.utils import formatdate, fmt_money, flt, cstr, cint, format_datetime, format_time from frappe.model.meta import get_field_currency, get_field_precision import re +from six import string_types def format_value(value, df=None, doc=None, currency=None, translated=False): '''Format value based on given fieldtype, document reference, currency reference. If docfield info (df) is not given, it will try and guess based on the datatype of the value''' - if isinstance(df, basestring): + if isinstance(df, string_types): df = frappe._dict(fieldtype=df) if not df: diff --git a/frappe/utils/html_utils.py b/frappe/utils/html_utils.py index 9824a64106..94c2563424 100644 --- a/frappe/utils/html_utils.py +++ b/frappe/utils/html_utils.py @@ -1,5 +1,6 @@ import json import bleach, bleach_whitelist +from six import string_types def sanitize_html(html, linkify=False): """ @@ -8,7 +9,7 @@ def sanitize_html(html, linkify=False): Does not sanitize JSON, as it could lead to future problems """ - if not isinstance(html, basestring): + if not isinstance(html, string_types): return html elif is_json(html): diff --git a/frappe/utils/make_random.py b/frappe/utils/make_random.py index e3ea5ba5b9..4b2f7688a5 100644 --- a/frappe/utils/make_random.py +++ b/frappe/utils/make_random.py @@ -1,5 +1,6 @@ import frappe, random from six.moves import range +from six import string_types settings = frappe._dict( prob = { @@ -15,7 +16,7 @@ def add_random_children(doc, fieldname, rows, randomize, unique=None): for i in range(nrows): d = {} for key, val in randomize.items(): - if isinstance(val[0], basestring): + if isinstance(val[0], string_types): d[key] = get_random(*val) else: d[key] = random.randrange(*val) diff --git a/frappe/utils/oauth.py b/frappe/utils/oauth.py index 8770ff56e9..61498a9722 100644 --- a/frappe/utils/oauth.py +++ b/frappe/utils/oauth.py @@ -6,6 +6,7 @@ import frappe import frappe.utils import json from frappe import _ +from six import string_types class SignupDisabledError(frappe.PermissionError): pass @@ -211,10 +212,10 @@ def login_oauth_user(data=None, provider=None, state=None, email_id=None, key=No # return # json.loads data and state - if isinstance(data, basestring): + if isinstance(data, string_types): data = json.loads(data) - if isinstance(state, basestring): + if isinstance(state, string_types): state = json.loads(state) if not (state and state["token"]): diff --git a/frappe/utils/scheduler.py b/frappe/utils/scheduler.py index 211bef028c..aaddc1958e 100755 --- a/frappe/utils/scheduler.py +++ b/frappe/utils/scheduler.py @@ -23,6 +23,7 @@ from frappe.limits import has_expired from frappe.utils.data import get_datetime, now_datetime from frappe.core.doctype.user.user import STANDARD_USERS from frappe.installer import update_site_config +from six import string_types DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S' @@ -192,7 +193,7 @@ def get_enabled_scheduler_events(): enabled_events = frappe.db.get_global("enabled_scheduler_events") if enabled_events: - if isinstance(enabled_events, basestring): + if isinstance(enabled_events, string_types): enabled_events = json.loads(enabled_events) return enabled_events diff --git a/frappe/utils/verified_command.py b/frappe/utils/verified_command.py index 57170295f8..c92f1a8e1a 100644 --- a/frappe/utils/verified_command.py +++ b/frappe/utils/verified_command.py @@ -8,12 +8,13 @@ from frappe import _ import frappe import frappe.utils +from six import string_types def get_signed_params(params): """Sign a url by appending `&_signature=xxxxx` to given params (string or dict). :param params: String or dict of parameters.""" - if not isinstance(params, basestring): + if not isinstance(params, string_types): params = urllib.urlencode(params) signature = hmac.new(params) diff --git a/frappe/utils/xlsxutils.py b/frappe/utils/xlsxutils.py index e41888a6cb..afd67cacaa 100644 --- a/frappe/utils/xlsxutils.py +++ b/frappe/utils/xlsxutils.py @@ -8,7 +8,7 @@ from frappe.utils import encode, cstr, cint, flt, comma_or import openpyxl from openpyxl.styles import Font from openpyxl import load_workbook -from six import StringIO +from six import StringIO, string_types # return xlsx file object @@ -23,7 +23,7 @@ def make_xlsx(data, sheet_name): for row in data: clean_row = [] for item in row: - if isinstance(item, basestring) and sheet_name != "Data Import Template": + if isinstance(item, string_types) and sheet_name != "Data Import Template": value = handle_html(item) else: value = item diff --git a/frappe/www/printview.py b/frappe/www/printview.py index 03782b9317..1ed4ee3782 100644 --- a/frappe/www/printview.py +++ b/frappe/www/printview.py @@ -10,6 +10,7 @@ from frappe.modules import get_doc_path from jinja2 import TemplateNotFound from frappe.utils import cint, strip_html from markdown2 import markdown +from six import string_types no_cache = 1 no_sitemap = 1 @@ -64,7 +65,7 @@ def get_html(doc, name=None, print_format=None, meta=None, print_settings = frappe.db.get_singles_dict("Print Settings") - if isinstance(no_letterhead, basestring): + if isinstance(no_letterhead, string_types): no_letterhead = cint(no_letterhead) elif no_letterhead is None: @@ -175,10 +176,10 @@ def get_html_and_style(doc, name=None, print_format=None, meta=None, no_letterhead=None, trigger_print=False): """Returns `html` and `style` of print format, used in PDF etc""" - if isinstance(doc, basestring) and isinstance(name, basestring): + if isinstance(doc, string_types) and isinstance(name, string_types): doc = frappe.get_doc(doc, name) - if isinstance(doc, basestring): + 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)) @@ -336,7 +337,7 @@ def has_value(df, doc): if value in (None, ""): return False - elif isinstance(value, basestring) and not strip_html(value).strip(): + elif isinstance(value, string_types) and not strip_html(value).strip(): return False elif isinstance(value, list) and not len(value): @@ -427,7 +428,7 @@ def column_has_value(data, fieldname): for row in data: value = row.get(fieldname) if value: - if isinstance(value, basestring): + if isinstance(value, string_types): if strip_html(value).strip(): has_value = True break From dfedd584ca8622da7fbc539fb76c7121944a4350 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 12:55:15 +0530 Subject: [PATCH 23/69] Explicitly convert dict.values() to list --- frappe/model/base_document.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 0151feac8e..5ba5ceea6f 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -296,7 +296,7 @@ class BaseDocument(object): doctype = self.doctype, columns = ", ".join(["`"+c+"`" for c in columns]), values = ", ".join(["%s"] * len(columns)) - ), d.values()) + ), list(d.values())) except Exception as e: if e.args[0]==1062: if "PRIMARY" in cstr(e.args[1]): @@ -338,7 +338,7 @@ class BaseDocument(object): set {values} where name=%s""".format( doctype = self.doctype, values = ", ".join(["`"+c+"`=%s" for c in columns]) - ), d.values() + [name]) + ), list(d.values()) + [name]) except Exception as e: if e.args[0]==1062 and "Duplicate" in cstr(e.args[1]): self.show_unique_validation_message(e) From 39af5d1f1cb7a11fb57d5bd460cdad4a69bdb854 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 15:16:10 +0530 Subject: [PATCH 24/69] Convert method name to string instead of encoding --- frappe/model/document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/document.py b/frappe/model/document.py index 3e8db22802..e46b36880d 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -662,7 +662,7 @@ class Document(BaseDocument): # hack! to run hooks even if method does not exist fn = lambda self, *args, **kwargs: None - fn.__name__ = method.encode("utf-8") + fn.__name__ = str(method) out = Document.hook(fn)(self, *args, **kwargs) self.run_email_alerts(method) From 69c255661df6678d1f16ca5f492b16a135c07c50 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 15:50:26 +0530 Subject: [PATCH 25/69] Replaced long with six.integer_types --- frappe/database.py | 8 ++++---- frappe/utils/data.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frappe/database.py b/frappe/database.py index b702a8c53d..00f54491d1 100644 --- a/frappe/database.py +++ b/frappe/database.py @@ -18,7 +18,7 @@ import redis import frappe.model.meta from frappe.utils import now, get_datetime, cstr from frappe import _ -from six import text_type, binary_type +from six import text_type, binary_type, integer_types from frappe.utils.global_search import sync_global_search from frappe.model.utils.link_count import flush_local_link_count from six import iteritems, text_type @@ -270,7 +270,7 @@ class Database: """Returns true if the first row in the result has a Date, Datetime, Long Int.""" if result and result[0]: for v in result[0]: - if isinstance(v, (datetime.date, datetime.timedelta, datetime.datetime, long)): + if isinstance(v, (datetime.date, datetime.timedelta, datetime.datetime, integer_types)): return True if formatted and isinstance(v, (int, float)): return True @@ -287,7 +287,7 @@ class Database: from frappe.utils import formatdate, fmt_money - if isinstance(v, (datetime.date, datetime.timedelta, datetime.datetime, long)): + if isinstance(v, (datetime.date, datetime.timedelta, datetime.datetime, integer_types)): if isinstance(v, datetime.date): v = text_type(v) if formatted: @@ -298,7 +298,7 @@ class Database: v = text_type(v) # long - elif isinstance(v, long): + elif isinstance(v, integer_types): v=int(v) # convert to strings... (if formatted) diff --git a/frappe/utils/data.py b/frappe/utils/data.py index a07cb61957..e01a8b7bc2 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -14,7 +14,7 @@ from num2words import num2words from six.moves import html_parser as HTMLParser from six.moves.urllib.parse import quote from html2text import html2text -from six import iteritems, text_type +from six import iteritems, text_type, integer_types DATE_FORMAT = "%Y-%m-%d" TIME_FORMAT = "%H:%M:%S.%f" @@ -346,7 +346,7 @@ def parse_val(v): v = text_type(v) elif isinstance(v, datetime.timedelta): v = ":".join(text_type(v).split(":")[:2]) - elif isinstance(v, long): + elif isinstance(v, integer_types): v = int(v) return v From 5cc6903cd5107b3289ef2ce441568a618e967ddf Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 16:11:24 +0530 Subject: [PATCH 26/69] Make sure that max_length[0][0] is comparable with new_length --- frappe/model/db_schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/db_schema.py b/frappe/model/db_schema.py index 37d644883e..e47c678e4c 100644 --- a/frappe/model/db_schema.py +++ b/frappe/model/db_schema.py @@ -127,7 +127,7 @@ class DbTable: else: raise - if max_length and max_length[0][0] > new_length: + if max_length and max_length[0][0] and max_length[0][0] > new_length: current_type = self.current_columns[col.fieldname]["type"] current_length = re.findall('varchar\(([\d]+)\)', current_type) if not current_length: From e324406c8a59f68eb404bc9f16811785cf1a9142 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 16:25:56 +0530 Subject: [PATCH 27/69] Import six.moves.urllib.parse.urlencode instead of urllib.urlencode --- frappe/api.py | 3 +-- .../doctype/paypal_settings/paypal_settings.py | 7 +++---- .../doctype/razorpay_settings/razorpay_settings.py | 9 +++++---- .../doctype/stripe_settings/stripe_settings.py | 8 ++++---- frappe/integrations/oauth2.py | 4 +--- frappe/limits.py | 6 +++--- frappe/utils/verified_command.py | 6 +++--- frappe/website/doctype/web_form/web_form.py | 2 +- 8 files changed, 21 insertions(+), 24 deletions(-) diff --git a/frappe/api.py b/frappe/api.py index 38c4598273..f99afb7a4f 100644 --- a/frappe/api.py +++ b/frappe/api.py @@ -8,8 +8,7 @@ import frappe.handler import frappe.client from frappe.utils.response import build_response from frappe import _ -from six.moves.urllib.parse import urlparse -from urllib import urlencode +from six.moves.urllib.parse import urlparse, urlencode def handle(): """ diff --git a/frappe/integrations/doctype/paypal_settings/paypal_settings.py b/frappe/integrations/doctype/paypal_settings/paypal_settings.py index b9d143b95f..36eff70fa1 100644 --- a/frappe/integrations/doctype/paypal_settings/paypal_settings.py +++ b/frappe/integrations/doctype/paypal_settings/paypal_settings.py @@ -60,9 +60,8 @@ import frappe import json from frappe import _ from frappe.utils import get_url, call_hook_method, cint -from urllib import urlencode +from six.moves.urllib.parse import urlencode from frappe.model.document import Document -import urllib from frappe.integrations.utils import create_request_log, make_post_request, create_payment_gateway class PayPalSettings(Document): @@ -237,9 +236,9 @@ def confirm_payment(token): redirect_url = "/integrations/payment-failed" if redirect_to: - redirect_url += '?' + urllib.urlencode({'redirect_to': redirect_to}) + redirect_url += '?' + urlencode({'redirect_to': redirect_to}) if redirect_message: - redirect_url += '&' + urllib.urlencode({'redirect_message': redirect_message}) + redirect_url += '&' + urlencode({'redirect_message': redirect_message}) # this is done so that functions called via hooks can update flags.redirect_to if redirect: diff --git a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py index c982424c96..9a79ef9bec 100644 --- a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py +++ b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py @@ -55,7 +55,8 @@ For razorpay payment status is Authorized from __future__ import unicode_literals import frappe from frappe import _ -import urllib, json +import json +from six.moves.urllib.parse import urlencode from frappe.model.document import Document from frappe.utils import get_url, call_hook_method, cint from frappe.integrations.utils import make_get_request, make_post_request, create_request_log, create_payment_gateway @@ -82,7 +83,7 @@ class RazorpaySettings(Document): frappe.throw(_("Please select another payment method. Razorpay does not support transactions in currency '{0}'").format(currency)) def get_payment_url(self, **kwargs): - return get_url("./integrations/razorpay_checkout?{0}".format(urllib.urlencode(kwargs))) + return get_url("./integrations/razorpay_checkout?{0}".format(urlencode(kwargs))) def create_request(self, data): self.data = frappe._dict(data) @@ -146,9 +147,9 @@ class RazorpaySettings(Document): redirect_url = 'payment-failed' if redirect_to: - redirect_url += '?' + urllib.urlencode({'redirect_to': redirect_to}) + redirect_url += '?' + urlencode({'redirect_to': redirect_to}) if redirect_message: - redirect_url += '&' + urllib.urlencode({'redirect_message': redirect_message}) + redirect_url += '&' + urlencode({'redirect_message': redirect_message}) return { "redirect_to": redirect_url, diff --git a/frappe/integrations/doctype/stripe_settings/stripe_settings.py b/frappe/integrations/doctype/stripe_settings/stripe_settings.py index 9966ff1049..d72b435667 100644 --- a/frappe/integrations/doctype/stripe_settings/stripe_settings.py +++ b/frappe/integrations/doctype/stripe_settings/stripe_settings.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document from frappe import _ -import urllib +from six.moves.urllib.parse import urlencode from frappe.utils import get_url, call_hook_method, cint from frappe.integrations.utils import make_get_request, make_post_request, create_request_log, create_payment_gateway @@ -42,7 +42,7 @@ class StripeSettings(Document): frappe.throw(_("Please select another payment method. Stripe does not support transactions in currency '{0}'").format(currency)) def get_payment_url(self, **kwargs): - return get_url("./integrations/stripe_checkout?{0}".format(urllib.urlencode(kwargs))) + return get_url("./integrations/stripe_checkout?{0}".format(urlencode(kwargs))) def create_request(self, data): self.data = frappe._dict(data) @@ -105,9 +105,9 @@ class StripeSettings(Document): redirect_url = 'payment-failed' if redirect_to: - redirect_url += '?' + urllib.urlencode({'redirect_to': redirect_to}) + redirect_url += '?' + urlencode({'redirect_to': redirect_to}) if redirect_message: - redirect_url += '&' + urllib.urlencode({'redirect_message': redirect_message}) + redirect_url += '&' + urlencode({'redirect_message': redirect_message}) return { "redirect_to": redirect_url, diff --git a/frappe/integrations/oauth2.py b/frappe/integrations/oauth2.py index 6889633c9b..7a5b616395 100644 --- a/frappe/integrations/oauth2.py +++ b/frappe/integrations/oauth2.py @@ -2,10 +2,8 @@ from __future__ import unicode_literals import frappe, json from frappe.oauth import OAuthWebRequestValidator, WebApplicationServer from oauthlib.oauth2 import FatalClientError, OAuth2Error -from urllib import urlencode -from six.moves.urllib.parse import quote from werkzeug import url_fix -from six.moves.urllib.parse import urlparse +from six.moves.urllib.parse import quote, urlencode, urlparse from frappe.integrations.doctype.oauth_provider_settings.oauth_provider_settings import get_oauth_settings from frappe import _ diff --git a/frappe/limits.py b/frappe/limits.py index 0f597e445f..a271b7c5d1 100755 --- a/frappe/limits.py +++ b/frappe/limits.py @@ -5,8 +5,8 @@ from frappe.utils import now_datetime, getdate, flt, cint, get_fullname from frappe.installer import update_site_config from frappe.utils.data import formatdate from frappe.utils.user import get_enabled_system_users, disable_users -import os, subprocess, urllib -from six.moves.urllib.parse import parse_qsl, urlsplit, urlunsplit +import os, subprocess +from six.moves.urllib.parse import parse_qsl, urlsplit, urlunsplit, urlencode class SiteExpiredError(frappe.ValidationError): http_status_code = 417 @@ -131,7 +131,7 @@ def get_upgrade_url(upgrade_url): 'country': frappe.db.get_value("System Settings", "System Settings", 'country') }) - query = urllib.urlencode(params, doseq=True) + query = urlencode(params, doseq=True) url = urlunsplit((parts.scheme, parts.netloc, parts.path, query, parts.fragment)) return url diff --git a/frappe/utils/verified_command.py b/frappe/utils/verified_command.py index 57170295f8..7ab493df23 100644 --- a/frappe/utils/verified_command.py +++ b/frappe/utils/verified_command.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import hmac -import urllib +from six.moves.urllib.parse import urlencode from frappe import _ import frappe @@ -14,7 +14,7 @@ def get_signed_params(params): :param params: String or dict of parameters.""" if not isinstance(params, basestring): - params = urllib.urlencode(params) + params = urlencode(params) signature = hmac.new(params) signature.update(get_secret()) @@ -49,7 +49,7 @@ def get_url(cmd, params, nonce=None, secret=None): nonce = params signature = get_signature(params, nonce, secret) params['signature'] = signature - return frappe.utils.get_url("".join(['api/method/', cmd, '?', urllib.urlencode(params)])) + return frappe.utils.get_url("".join(['api/method/', cmd, '?', urlencode(params)])) def get_signature(params, nonce, secret=None): params = "".join((frappe.utils.cstr(p) for p in params.values())) diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py index 6abe0d0d9e..182d385c5f 100644 --- a/frappe/website/doctype/web_form/web_form.py +++ b/frappe/website/doctype/web_form/web_form.py @@ -11,7 +11,7 @@ from frappe.website.utils import get_comment_list from frappe.custom.doctype.customize_form.customize_form import docfield_properties from frappe.utils.file_manager import get_max_file_size from frappe.modules.utils import export_module_json, get_doc_module -from urllib import urlencode +from six.moves.urllib.parse import urlencode from frappe.integrations.utils import get_payment_gateway_controller from six import iteritems From 2da880fc4202ab5135789a00649604320608a282 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 16:36:17 +0530 Subject: [PATCH 28/69] Replace Py2 raise syntax with Py 3 --- frappe/model/db_query.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py index 205fd3a1e7..61bc4bff21 100644 --- a/frappe/model/db_query.py +++ b/frappe/model/db_query.py @@ -37,7 +37,7 @@ class DatabaseQuery(object): update=None, add_total_row=None, user_settings=None): if not ignore_permissions and not frappe.has_permission(self.doctype, "read", user=user): frappe.flags.error_message = _('Insufficient Permission for {0}').format(frappe.bold(self.doctype)) - raise frappe.PermissionError, self.doctype + raise frappe.PermissionError(self.doctype) # fitlers and fields swappable # its hard to remember what comes first @@ -203,7 +203,7 @@ class DatabaseQuery(object): doctype = table_name[4:-1] if (not self.flags.ignore_permissions) and (not frappe.has_permission(doctype)): frappe.flags.error_message = _('Insufficient Permission for {0}').format(frappe.bold(doctype)) - raise frappe.PermissionError, doctype + raise frappe.PermissionError(doctype) def set_field_tables(self): '''If there are more than one table, the fieldname must not be ambigous. From 000d9a41b6cecaff66c7a9c218a0453a6620fa0f Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 19:06:52 +0530 Subject: [PATCH 29/69] Use PyPDF2 instead of pyPdf --- frappe/utils/pdf.py | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/utils/pdf.py b/frappe/utils/pdf.py index 4924fbaa9d..332eaa738d 100644 --- a/frappe/utils/pdf.py +++ b/frappe/utils/pdf.py @@ -6,7 +6,7 @@ import pdfkit, os, frappe from frappe.utils import scrub_urls from frappe import _ from bs4 import BeautifulSoup -from pyPdf import PdfFileWriter, PdfFileReader +from PyPDF2 import PdfFileWriter, PdfFileReader def get_pdf(html, options=None, output = None): html = scrub_urls(html) diff --git a/requirements.txt b/requirements.txt index 4dfaa5f9c5..8ceebefa0b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -42,7 +42,7 @@ psutil unittest-xml-reporting oauthlib PyJWT -pypdf +PyPDF2 openpyxl pyotp pyqrcode From 29dfc26a760dffaefd2651b039ad2ed3aee4c2a9 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 19:18:48 +0530 Subject: [PATCH 30/69] Import six.StringIO instead of StringIO.StringIO --- frappe/twofactor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/twofactor.py b/frappe/twofactor.py index bb796fd296..09771e3e3b 100644 --- a/frappe/twofactor.py +++ b/frappe/twofactor.py @@ -9,7 +9,7 @@ import pyotp, os from frappe.utils.background_jobs import enqueue from jinja2 import Template from pyqrcode import create as qrcreate -from StringIO import StringIO +from six import StringIO from base64 import b64encode, b32encode from frappe.utils import get_url, get_datetime, time_diff_in_seconds From 2403a800c0eccae1b1ed1ca1de441bf28e6bac81 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Fri, 11 Aug 2017 12:56:59 +0530 Subject: [PATCH 31/69] Use absolute import for frappe.twofactor (#3915) --- frappe/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/auth.py b/frappe/auth.py index bd510b9fcd..b92e7e604d 100644 --- a/frappe/auth.py +++ b/frappe/auth.py @@ -17,7 +17,7 @@ from frappe.translate import get_lang_code from frappe.utils.password import check_password from frappe.core.doctype.authentication_log.authentication_log import add_authentication_log from frappe.utils.background_jobs import enqueue -from twofactor import (should_run_2fa, authenticate_for_2factor, +from frappe.twofactor import (should_run_2fa, authenticate_for_2factor, confirm_otp_token, get_cached_user_pass) from six.moves.urllib.parse import quote From 7397b6829031879119da34c31890a0f3f1569471 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 11 Aug 2017 13:00:10 +0530 Subject: [PATCH 32/69] Scrub urls fix (#3918) * Don't expand mailto urls * Add test case --- frappe/tests/test_utils.py | 30 ++++++++++++++++++++++++++++-- frappe/utils/data.py | 8 +++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/frappe/tests/test_utils.py b/frappe/tests/test_utils.py index af13829e7e..948e26a74f 100644 --- a/frappe/tests/test_utils.py +++ b/frappe/tests/test_utils.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import unittest -from frappe.utils import evaluate_filters, money_in_words +from frappe.utils import evaluate_filters, money_in_words, scrub_urls, get_url class TestFilters(unittest.TestCase): def test_simple_dict(self): @@ -57,4 +57,30 @@ class TestMoney(unittest.TestCase): self.assertEqual( money_in_words(num[0], "NGN"), num[1], "{0} is not the same as {1}". format(money_in_words(num[0], "NGN"), num[1]) - ) \ No newline at end of file + ) + +class TestDataManipulation(unittest.TestCase): + def test_scrub_urls(self): + html = ''' +

You have a new message from: John

+

Hey, wassup!

+ +
+ Please mail us at email +
+ ''' + + html = scrub_urls(html) + url = get_url() + + self.assertTrue('Test link 1' in html) + self.assertTrue('Test link 2'.format(url) in html) + self.assertTrue('Test link 3'.format(url) in html) + self.assertTrue(''.format(url) in html) + self.assertTrue('style="background-image: url(\'{0}/assets/frappe/bg.jpg\') !important"'.format(url) in html) + self.assertTrue('email' in html) diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 8408b4f5aa..8de7e3266f 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -778,9 +778,11 @@ def expand_relative_urls(html): def _expand_relative_urls(match): to_expand = list(match.groups()) - if not to_expand[2].startswith("/"): - to_expand[2] = "/" + to_expand[2] - to_expand.insert(2, url) + + if not to_expand[2].startswith('mailto'): + if not to_expand[2].startswith("/"): + to_expand[2] = "/" + to_expand[2] + to_expand.insert(2, url) if 'url' in to_expand[0] and to_expand[1].startswith('(') and to_expand[-1].endswith(')'): # background-image: url('/assets/...') - workaround for wkhtmltopdf print-media-type From 9c03e3aef768974fa2fda2f399e338a1d5c657f7 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 11 Aug 2017 14:22:15 +0530 Subject: [PATCH 33/69] [fix] pypdf > pydf2 --- frappe/utils/print_format.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index 0528ae25d1..f0ba734eac 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -7,7 +7,7 @@ from frappe.modules import get_doc_path from jinja2 import TemplateNotFound from frappe.utils import cint, strip_html from frappe.utils.pdf import get_pdf -from pyPdf import PdfFileWriter, PdfFileReader +from pyPDF2 import PdfFileWriter, PdfFileReader no_cache = 1 no_sitemap = 1 From 6031d704dce0c502983dcd0113dad28813eeeac7 Mon Sep 17 00:00:00 2001 From: Manas Solanki Date: Fri, 11 Aug 2017 14:39:53 +0530 Subject: [PATCH 34/69] fix the typos (#3919) --- frappe/email/doctype/newsletter/newsletter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/email/doctype/newsletter/newsletter.py b/frappe/email/doctype/newsletter/newsletter.py index 04790de8b6..1813b01c53 100755 --- a/frappe/email/doctype/newsletter/newsletter.py +++ b/frappe/email/doctype/newsletter/newsletter.py @@ -72,13 +72,13 @@ class Newsletter(Document): files = frappe.get_all("File", fields = ["name"], filters = {"attached_to_doctype": "Newsletter", "attached_to_name":self.name}, order_by="creation desc") - for a in files: + for file in files: try: # these attachments will be attached on-demand # and won't be stored in the message attachments.append({"fid": file.name}) except IOError: - frappe.throw(_("Unable to find attachment {0}").format(a)) + frappe.throw(_("Unable to find attachment {0}").format(file.name)) send(recipients = self.recipients, sender = sender, subject = self.subject, message = self.message, From 5472f2c32789e1bdee92e373c5253162702bdceb Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 11 Aug 2017 16:09:05 +0530 Subject: [PATCH 35/69] [fix] pypdf > pydf2 --- frappe/utils/print_format.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index f0ba734eac..17d6eb2fde 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -7,7 +7,7 @@ from frappe.modules import get_doc_path from jinja2 import TemplateNotFound from frappe.utils import cint, strip_html from frappe.utils.pdf import get_pdf -from pyPDF2 import PdfFileWriter, PdfFileReader +from PyPDF2 import PdfFileWriter, PdfFileReader no_cache = 1 no_sitemap = 1 From 4b730e0a2042a5ad60fdce2582a06592b115ea07 Mon Sep 17 00:00:00 2001 From: Makarand Bauskar Date: Fri, 11 Aug 2017 16:36:05 +0530 Subject: [PATCH 36/69] [minor] fixed pypdf2 import typo in print_format.py (#3921) From 4b163431c0f8367a9fb5bf33b2349c402ba36fa3 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Fri, 11 Aug 2017 17:18:25 +0530 Subject: [PATCH 37/69] Use repr() instead of backticks --- frappe/utils/error.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/error.py b/frappe/utils/error.py index b117c4ad21..7c4d13ac1f 100644 --- a/frappe/utils/error.py +++ b/frappe/utils/error.py @@ -64,7 +64,7 @@ def get_snapshot(exception, context=10): 'traceback': traceback.format_exc(), 'frames': [], 'etype': cstr(etype), - 'evalue': cstr(`evalue`), + 'evalue': cstr(repr(evalue)), 'exception': {}, 'locals': {} } From 0a6ecbf2c5033aa55e56b825b7c13fca0509bcaf Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Fri, 11 Aug 2017 18:09:32 +0530 Subject: [PATCH 38/69] Don't unnecessarily encode os.path.join() --- frappe/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/app.py b/frappe/app.py index eb42948cfd..84df9e7a0b 100644 --- a/frappe/app.py +++ b/frappe/app.py @@ -213,11 +213,11 @@ def serve(port=8000, profile=False, site=None, sites_path='.'): if not os.environ.get('NO_STATICS'): application = SharedDataMiddleware(application, { - b'/assets': os.path.join(sites_path, 'assets').encode("utf-8"), + b'/assets': os.path.join(sites_path, 'assets'), }) application = StaticDataMiddleware(application, { - b'/files': os.path.abspath(sites_path).encode("utf-8") + b'/files': os.path.abspath(sites_path) }) application.debug = True From e0b30b1f532dba1d4723c60f4b9695e1477cb0ba Mon Sep 17 00:00:00 2001 From: ci2014 Date: Fri, 11 Aug 2017 19:25:19 +0200 Subject: [PATCH 39/69] Update file.py Give developers the ability to generate several sizes of thumbnails. --- frappe/core/doctype/file/file.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index 4be9693125..a27d183fe4 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -170,7 +170,7 @@ class File(NestedSet): super(File, self).on_trash() self.delete_file() - def make_thumbnail(self): + def make_thumbnail(self, set_as_thumbnail=True, width=300, height=300, suffix="small"): if self.file_url: if self.file_url.startswith("/files"): try: @@ -184,15 +184,19 @@ class File(NestedSet): except (requests.exceptions.HTTPError, requests.exceptions.SSLError, IOError): return - size = 300, 300 + size = width, height image.thumbnail(size) - thumbnail_url = filename + "_small." + extn + thumbnail_url = filename + "_" + suffix + "." + extn path = os.path.abspath(frappe.get_site_path("public", thumbnail_url.lstrip("/"))) try: image.save(path) + + if set_as_thumbnail: + self.db_set("thumbnail_url", thumbnail_url) + self.db_set("thumbnail_url", thumbnail_url) except IOError: frappe.msgprint(_("Unable to write file format for {0}").format(path)) From 05c88fa3f0dfa11c69777aef1ba6acb6105dc6df Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 14 Aug 2017 12:58:32 +0530 Subject: [PATCH 40/69] [minor] make email alert configurable, so we can use it list default print formats --- .../doctype/email_alert/email_alert.json | 4 +- .../email/doctype/email_alert/email_alert.py | 42 ++++++++++++------- .../doctype/email_alert/test_email_alert.js | 23 ++++++++++ frappe/model/sync.py | 2 +- frappe/modules/import_file.py | 5 ++- frappe/public/css/form.css | 9 ++++ frappe/public/js/frappe/form/control.js | 2 +- frappe/public/less/form.less | 10 +++++ 8 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 frappe/email/doctype/email_alert/test_email_alert.js diff --git a/frappe/email/doctype/email_alert/email_alert.json b/frappe/email/doctype/email_alert/email_alert.json index 095f0a9c18..197705b89e 100755 --- a/frappe/email/doctype/email_alert/email_alert.json +++ b/frappe/email/doctype/email_alert/email_alert.json @@ -681,7 +681,7 @@ "collapsible": 0, "columns": 0, "default": "Add your message here", - "depends_on": "eval:!doc.is_standard", + "depends_on": "", "fieldname": "message", "fieldtype": "Code", "hidden": 0, @@ -808,7 +808,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2017-07-07 16:09:48.804218", + "modified": "2017-08-13 22:43:49.079330", "modified_by": "Administrator", "module": "Email", "name": "Email Alert", diff --git a/frappe/email/doctype/email_alert/email_alert.py b/frappe/email/doctype/email_alert/email_alert.py index 8ef2423299..4dfa877856 100755 --- a/frappe/email/doctype/email_alert/email_alert.py +++ b/frappe/email/doctype/email_alert/email_alert.py @@ -7,14 +7,18 @@ import json, os from frappe import _ from frappe.model.document import Document from frappe.core.doctype.role.role import get_emails_from_role -from frappe.utils import validate_email_add, nowdate -from frappe.utils.data import parse_val +from frappe.utils import validate_email_add, nowdate, parse_val, is_html from frappe.utils.jinja import validate_template from frappe.modules.utils import export_module_json, get_doc_module from markdown2 import markdown from six import string_types class EmailAlert(Document): + def onload(self): + '''load message''' + if self.is_standard: + self.message = self.get_template() + def autoname(self): if not self.name: self.name = self.subject @@ -31,6 +35,7 @@ class EmailAlert(Document): self.validate_forbidden_types() self.validate_condition() + self.validate_standard() def on_update(self): frappe.cache().hdel('email_alerts', self.document_type) @@ -53,6 +58,10 @@ def get_context(context): pass """) + def validate_standard(self): + if self.is_standard and not frappe.conf.developer_mode: + frappe.throw(_('Cannot edit Standard Email Alert. To edit, please disable this and duplicate it')) + def validate_condition(self): temp_doc = frappe.new_doc(self.document_type) if self.condition: @@ -165,26 +174,31 @@ def get_context(context): self.property_value, update_modified = False) doc.set(self.set_property_after_alert, self.property_value) + def get_template(self): + module = get_doc_module(self.module, self.doctype, self.name) + def load_template(extn): + template = '' + template_path = os.path.join(os.path.dirname(module.__file__), + frappe.scrub(self.name) + extn) + if os.path.exists(template_path): + with open(template_path, 'r') as f: + template = f.read() + return template + + return load_template('.html') or load_template('.md') + def load_standard_properties(self, context): + '''load templates and run get_context''' module = get_doc_module(self.module, self.doctype, self.name) if module: if hasattr(module, 'get_context'): out = module.get_context(context) if out: context.update(out) - def load_template(extn): - template_path = os.path.join(os.path.dirname(module.__file__), - frappe.scrub(self.name) + extn) - if os.path.exists(template_path): - with open(template_path, 'r') as f: - self.message = f.read() - return True - - # get template - if not load_template('.html'): - if load_template('.md'): - self.message = markdown(self.message) + self.message = self.get_template() + if not is_html(self.message): + self.message = markdown(self.message) @frappe.whitelist() def get_documents_for_today(email_alert): diff --git a/frappe/email/doctype/email_alert/test_email_alert.js b/frappe/email/doctype/email_alert/test_email_alert.js new file mode 100644 index 0000000000..58b0de5f14 --- /dev/null +++ b/frappe/email/doctype/email_alert/test_email_alert.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Email Alert", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Email Alert + () => frappe.tests.make('Email Alert', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/frappe/model/sync.py b/frappe/model/sync.py index c002136321..72e80a9ecc 100644 --- a/frappe/model/sync.py +++ b/frappe/model/sync.py @@ -42,7 +42,7 @@ def sync_for(app_name, force=0, sync_everything = False, verbose=False, reset_pe if l: for i, doc_path in enumerate(files): import_file_by_path(doc_path, force=force, ignore_version=True, - reset_permissions=reset_permissions) + reset_permissions=reset_permissions, for_sync=True) #print module_name + ' | ' + doctype + ' | ' + name frappe.db.commit() diff --git a/frappe/modules/import_file.py b/frappe/modules/import_file.py index 57c671b407..9a2c080d9b 100644 --- a/frappe/modules/import_file.py +++ b/frappe/modules/import_file.py @@ -33,7 +33,7 @@ def get_file_path(module, dt, dn): return path def import_file_by_path(path, force=False, data_import=False, pre_process=None, ignore_version=None, - reset_permissions=False): + reset_permissions=False, for_sync=False): try: docs = read_doc_from_file(path) except IOError: @@ -86,7 +86,8 @@ def read_doc_from_file(path): ignore_values = { "Report": ["disabled"], - "Print Format": ["disabled"] + "Print Format": ["disabled"], + "Email Alert": ["enabled"] } ignore_doctypes = [""] diff --git a/frappe/public/css/form.css b/frappe/public/css/form.css index 2dd5aaa1e2..00674934af 100644 --- a/frappe/public/css/form.css +++ b/frappe/public/css/form.css @@ -588,6 +588,15 @@ select.form-control { .password-strength-message { margin-top: -10px; } +.control-code { + height: 400px; + font-family: Monaco, "Courier New", monospace; + background-color: black; + color: #fffce7; + font-size: 12px; + line-height: 1.7em; + border: none; +} .delivery-status-indicator { display: inline-block; margin-top: -3px; diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js index fa738c8190..70e6c8216c 100755 --- a/frappe/public/js/frappe/form/control.js +++ b/frappe/public/js/frappe/form/control.js @@ -1802,7 +1802,7 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({ this._super(); $(this.input_area).find("textarea") .allowTabs() - .css({"height":"400px", "font-family": "Monaco, \"Courier New\", monospace"}); + .addClass('control-code'); } }); diff --git a/frappe/public/less/form.less b/frappe/public/less/form.less index 3440d6f4b5..e9c80cb84c 100644 --- a/frappe/public/less/form.less +++ b/frappe/public/less/form.less @@ -735,6 +735,16 @@ select.form-control { margin-top: -10px; } +.control-code { + height: 400px; + font-family: Monaco, "Courier New", monospace; + background-color: black; + color: @light-yellow; + font-size: 12px; + line-height: 1.7em; + border: none; +} + .delivery-status-indicator { display: inline-block; margin-top: -3px; From 65794892dea8d57385fc8423b0bacae3bdda1ef9 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 16 Aug 2017 13:15:30 +0530 Subject: [PATCH 41/69] Currency precision: remove trailing zeros --- frappe/utils/data.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 8de7e3266f..825f100e0d 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -363,6 +363,17 @@ def fmt_money(amount, precision=None, currency=None): if precision is None: precision = number_format_precision + # 40,000 -> 40,000.00 + # 40,000.00000 -> 40,000.00 + # 40,000.23000 -> 40,000.23 + parts = str(amount).split(decimal_str) + decimals = parts[1] if len(parts) > 1 else '' + if precision > 2: + if len(decimals) < 3: + precision = 2 + elif len(decimals) < precision: + precision = len(decimals) + amount = '%.*f' % (precision, flt(amount)) if amount.find('.') == -1: decimals = '' From 1dc9baf9d3b15030cec8537d7935b86dd0871a56 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 16 Aug 2017 13:15:35 +0530 Subject: [PATCH 42/69] Add tests --- frappe/tests/test_utils.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/frappe/tests/test_utils.py b/frappe/tests/test_utils.py index 948e26a74f..6981e7122b 100644 --- a/frappe/tests/test_utils.py +++ b/frappe/tests/test_utils.py @@ -4,7 +4,8 @@ from __future__ import unicode_literals import unittest -from frappe.utils import evaluate_filters, money_in_words, scrub_urls, get_url +from frappe.utils import evaluate_filters, money_in_words, scrub_urls, get_url,\ + fmt_money class TestFilters(unittest.TestCase): def test_simple_dict(self): @@ -59,6 +60,27 @@ class TestMoney(unittest.TestCase): format(money_in_words(num[0], "NGN"), num[1]) ) + def test_fmt_money(self): + input = [40000, 40000.23, 40000.4567] + + output = ['40,000.00', '40,000.23', '40,000.4567'] + precision = 5 + self.assertEqual(fmt_money(input[0], precision), output[0]) + self.assertEqual(fmt_money(input[1], precision), output[1]) + self.assertEqual(fmt_money(input[2], precision), output[2]) + + output = ['40,000.00', '40,000.23', '40,000.457'] + precision = 3 + self.assertEqual(fmt_money(input[0], precision), output[0]) + self.assertEqual(fmt_money(input[1], precision), output[1]) + self.assertEqual(fmt_money(input[2], precision), output[2]) + + output = ['40,000.0', '40,000.2', '40,000.5'] + precision = 1 + self.assertEqual(fmt_money(input[0], precision), output[0]) + self.assertEqual(fmt_money(input[1], precision), output[1]) + self.assertEqual(fmt_money(input[2], precision), output[2]) + class TestDataManipulation(unittest.TestCase): def test_scrub_urls(self): html = ''' From af74d7a72966150111dabed52a274c335af98805 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 16 Aug 2017 16:04:41 +0530 Subject: [PATCH 43/69] codacy fix --- frappe/tests/test_utils.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/frappe/tests/test_utils.py b/frappe/tests/test_utils.py index 6981e7122b..b875798077 100644 --- a/frappe/tests/test_utils.py +++ b/frappe/tests/test_utils.py @@ -61,25 +61,25 @@ class TestMoney(unittest.TestCase): ) def test_fmt_money(self): - input = [40000, 40000.23, 40000.4567] + input_value = [40000, 40000.23, 40000.4567] - output = ['40,000.00', '40,000.23', '40,000.4567'] + output_value = ['40,000.00', '40,000.23', '40,000.4567'] precision = 5 - self.assertEqual(fmt_money(input[0], precision), output[0]) - self.assertEqual(fmt_money(input[1], precision), output[1]) - self.assertEqual(fmt_money(input[2], precision), output[2]) + self.assertEqual(fmt_money(input_value[0], precision), output_value[0]) + self.assertEqual(fmt_money(input_value[1], precision), output_value[1]) + self.assertEqual(fmt_money(input_value[2], precision), output_value[2]) - output = ['40,000.00', '40,000.23', '40,000.457'] + output_value = ['40,000.00', '40,000.23', '40,000.457'] precision = 3 - self.assertEqual(fmt_money(input[0], precision), output[0]) - self.assertEqual(fmt_money(input[1], precision), output[1]) - self.assertEqual(fmt_money(input[2], precision), output[2]) + self.assertEqual(fmt_money(input_value[0], precision), output_value[0]) + self.assertEqual(fmt_money(input_value[1], precision), output_value[1]) + self.assertEqual(fmt_money(input_value[2], precision), output_value[2]) - output = ['40,000.0', '40,000.2', '40,000.5'] + output_value = ['40,000.0', '40,000.2', '40,000.5'] precision = 1 - self.assertEqual(fmt_money(input[0], precision), output[0]) - self.assertEqual(fmt_money(input[1], precision), output[1]) - self.assertEqual(fmt_money(input[2], precision), output[2]) + self.assertEqual(fmt_money(input_value[0], precision), output_value[0]) + self.assertEqual(fmt_money(input_value[1], precision), output_value[1]) + self.assertEqual(fmt_money(input_value[2], precision), output_value[2]) class TestDataManipulation(unittest.TestCase): def test_scrub_urls(self): From 2243fe154c251bb9822599f3c0adba99af227a4d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 17 Aug 2017 10:55:54 +0530 Subject: [PATCH 44/69] minor fix in email queue status patch --- frappe/patches/v8_7/update_email_queue_status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/patches/v8_7/update_email_queue_status.py b/frappe/patches/v8_7/update_email_queue_status.py index 8dcbcc57d6..1e9be8e3cc 100644 --- a/frappe/patches/v8_7/update_email_queue_status.py +++ b/frappe/patches/v8_7/update_email_queue_status.py @@ -7,7 +7,7 @@ def execute(): default_email_account = get_default_outgoing_email_account() if frappe.conf.get("google_analytics_id") == "UA-8911157-19" or \ - default_email_account.email_id == "notifications@erpnext.com": + (default_email_account and default_email_account.email_id == "notifications@erpnext.com"): frappe.db.sql("""update `tabEmail Queue` set status='Not Sent' where creation>=DATE_SUB(NOW(), INTERVAL 16 HOUR)""") \ No newline at end of file From 18538184d79537667e4de480b7ace054f35eb7ad Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 17 Aug 2017 11:51:35 +0530 Subject: [PATCH 45/69] Fix fmt_money tests --- frappe/tests/test_fmt_money.py | 24 ++++++++++++++++-------- frappe/tests/test_utils.py | 21 --------------------- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/frappe/tests/test_fmt_money.py b/frappe/tests/test_fmt_money.py index 80afdc8791..b46b31d8dd 100644 --- a/frappe/tests/test_fmt_money.py +++ b/frappe/tests/test_fmt_money.py @@ -66,14 +66,22 @@ class TestFmtMoney(unittest.TestCase): def test_currency_precision(self): frappe.db.set_default("currency_precision", "4") frappe.db.set_default("number_format", "#,###.##") - self.assertEquals(fmt_money(100), "100.0000") - self.assertEquals(fmt_money(1000), "1,000.0000") - self.assertEquals(fmt_money(10000), "10,000.0000") - self.assertEquals(fmt_money(100000), "100,000.0000") - self.assertEquals(fmt_money(1000000), "1,000,000.0000") - self.assertEquals(fmt_money(10000000), "10,000,000.0000") - self.assertEquals(fmt_money(100000000), "100,000,000.0000") - self.assertEquals(fmt_money(1000000000), "1,000,000,000.0000") + self.assertEquals(fmt_money(100), "100.00") + self.assertEquals(fmt_money(1000), "1,000.00") + self.assertEquals(fmt_money(10000), "10,000.00") + self.assertEquals(fmt_money(100000), "100,000.00") + self.assertEquals(fmt_money(1000000), "1,000,000.00") + self.assertEquals(fmt_money(10000000), "10,000,000.00") + self.assertEquals(fmt_money(100000000), "100,000,000.00") + self.assertEquals(fmt_money(1000000000), "1,000,000,000.00") + self.assertEquals(fmt_money(100.23), "100.23") + self.assertEquals(fmt_money(1000.456), "1,000.456") + self.assertEquals(fmt_money(10000.7890), "10,000.789") + self.assertEquals(fmt_money(100000.1234), "100,000.1234") + self.assertEquals(fmt_money(1000000.3456), "1,000,000.3456") + self.assertEquals(fmt_money(10000000.3344567), "10,000,000.3345") + self.assertEquals(fmt_money(100000000.37827268), "100,000,000.378") + self.assertEquals(fmt_money(1000000000.2718272637), "1,000,000,000.27") frappe.db.set_default("currency_precision", "") if __name__=="__main__": diff --git a/frappe/tests/test_utils.py b/frappe/tests/test_utils.py index b875798077..ad57449bf9 100644 --- a/frappe/tests/test_utils.py +++ b/frappe/tests/test_utils.py @@ -60,27 +60,6 @@ class TestMoney(unittest.TestCase): format(money_in_words(num[0], "NGN"), num[1]) ) - def test_fmt_money(self): - input_value = [40000, 40000.23, 40000.4567] - - output_value = ['40,000.00', '40,000.23', '40,000.4567'] - precision = 5 - self.assertEqual(fmt_money(input_value[0], precision), output_value[0]) - self.assertEqual(fmt_money(input_value[1], precision), output_value[1]) - self.assertEqual(fmt_money(input_value[2], precision), output_value[2]) - - output_value = ['40,000.00', '40,000.23', '40,000.457'] - precision = 3 - self.assertEqual(fmt_money(input_value[0], precision), output_value[0]) - self.assertEqual(fmt_money(input_value[1], precision), output_value[1]) - self.assertEqual(fmt_money(input_value[2], precision), output_value[2]) - - output_value = ['40,000.0', '40,000.2', '40,000.5'] - precision = 1 - self.assertEqual(fmt_money(input_value[0], precision), output_value[0]) - self.assertEqual(fmt_money(input_value[1], precision), output_value[1]) - self.assertEqual(fmt_money(input_value[2], precision), output_value[2]) - class TestDataManipulation(unittest.TestCase): def test_scrub_urls(self): html = ''' From b501964e1cbe75909d4b976c0a221b5dfaa84c1b Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 17 Aug 2017 11:57:13 +0530 Subject: [PATCH 46/69] fix test --- frappe/utils/data.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 825f100e0d..9588038058 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -366,13 +366,14 @@ def fmt_money(amount, precision=None, currency=None): # 40,000 -> 40,000.00 # 40,000.00000 -> 40,000.00 # 40,000.23000 -> 40,000.23 - parts = str(amount).split(decimal_str) - decimals = parts[1] if len(parts) > 1 else '' - if precision > 2: - if len(decimals) < 3: - precision = 2 - elif len(decimals) < precision: - precision = len(decimals) + if decimal_str: + parts = str(amount).split(decimal_str) + decimals = parts[1] if len(parts) > 1 else '' + if precision > 2: + if len(decimals) < 3: + precision = 2 + elif len(decimals) < precision: + precision = len(decimals) amount = '%.*f' % (precision, flt(amount)) if amount.find('.') == -1: From 80b9e5aa3c5a7da284723757c0799f8cf5cb1a0e Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 17 Aug 2017 12:50:15 +0530 Subject: [PATCH 47/69] fix codacy --- frappe/tests/test_utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frappe/tests/test_utils.py b/frappe/tests/test_utils.py index ad57449bf9..948e26a74f 100644 --- a/frappe/tests/test_utils.py +++ b/frappe/tests/test_utils.py @@ -4,8 +4,7 @@ from __future__ import unicode_literals import unittest -from frappe.utils import evaluate_filters, money_in_words, scrub_urls, get_url,\ - fmt_money +from frappe.utils import evaluate_filters, money_in_words, scrub_urls, get_url class TestFilters(unittest.TestCase): def test_simple_dict(self): From 19e9834850f52c461595b15c24dadc4f1752d927 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 17 Aug 2017 18:34:14 +0530 Subject: [PATCH 48/69] [added] print style --- frappe/app.py | 9 +- frappe/boot.py | 2 + .../desk/page/setup_wizard/setup_wizard.css | 9 +- frappe/modules/import_file.py | 3 +- frappe/modules/utils.py | 5 +- .../print_settings/print_settings.json | 6 +- .../print_settings/test_print_settings.js | 23 ++ .../printing/doctype/print_style/__init__.py | 0 .../doctype/print_style/print_style.js | 8 + .../doctype/print_style/print_style.json | 214 ++++++++++++++++++ .../doctype/print_style/print_style.py | 23 ++ .../doctype/print_style/test_print_style.js | 23 ++ .../doctype/print_style/test_print_style.py | 10 + frappe/printing/print_style/__init__.py | 0 .../printing/print_style/classic/__init__.py | 0 .../printing/print_style/classic/classic.json | 14 ++ .../printing/print_style/modern/__init__.py | 0 .../printing/print_style/modern/modern.json | 14 ++ .../print_style/monochrome/__init__.py | 0 .../print_style/monochrome/monochrome.json | 14 ++ frappe/public/css/form.css | 9 +- frappe/public/js/frappe/dom.js | 1 + frappe/public/js/frappe/form/print.js | 23 +- .../frappe/form/templates/print_layout.html | 4 +- frappe/public/less/form.less | 9 +- frappe/templates/styles/classic.css | 16 -- frappe/templates/styles/modern.css | 19 -- frappe/templates/styles/monochrome.css | 26 --- frappe/website/render.py | 3 +- frappe/www/404.html | 12 + frappe/www/printview.py | 13 +- 31 files changed, 420 insertions(+), 92 deletions(-) create mode 100644 frappe/printing/doctype/print_settings/test_print_settings.js create mode 100644 frappe/printing/doctype/print_style/__init__.py create mode 100644 frappe/printing/doctype/print_style/print_style.js create mode 100644 frappe/printing/doctype/print_style/print_style.json create mode 100644 frappe/printing/doctype/print_style/print_style.py create mode 100644 frappe/printing/doctype/print_style/test_print_style.js create mode 100644 frappe/printing/doctype/print_style/test_print_style.py create mode 100644 frappe/printing/print_style/__init__.py create mode 100644 frappe/printing/print_style/classic/__init__.py create mode 100644 frappe/printing/print_style/classic/classic.json create mode 100644 frappe/printing/print_style/modern/__init__.py create mode 100644 frappe/printing/print_style/modern/modern.json create mode 100644 frappe/printing/print_style/monochrome/__init__.py create mode 100644 frappe/printing/print_style/monochrome/monochrome.json delete mode 100644 frappe/templates/styles/classic.css delete mode 100644 frappe/templates/styles/modern.css delete mode 100644 frappe/templates/styles/monochrome.css diff --git a/frappe/app.py b/frappe/app.py index 84df9e7a0b..2cd714fa9f 100644 --- a/frappe/app.py +++ b/frappe/app.py @@ -150,13 +150,13 @@ def handle_exception(e): elif http_status_code==403: frappe.respond_as_web_page(_("Not Permitted"), _("You do not have enough permissions to complete the action"), - http_status_code=http_status_code, indicator_color='red') + http_status_code=http_status_code, indicator_color='red', fullpage=True) return_as_message = True elif http_status_code==404: frappe.respond_as_web_page(_("Not Found"), _("The resource you are looking for is not available"), - http_status_code=http_status_code, indicator_color='red') + http_status_code=http_status_code, indicator_color='red', fullpage=True) return_as_message = True else: @@ -166,7 +166,7 @@ def handle_exception(e): frappe.respond_as_web_page("Server Error", traceback, http_status_code=http_status_code, - indicator_color='red') + indicator_color='red', fullpage=True) return_as_message = True if e.__class__ == frappe.AuthenticationError: @@ -178,7 +178,8 @@ def handle_exception(e): make_error_snapshot(e) if return_as_message: - response = frappe.website.render.render("message", http_status_code=http_status_code) + response = frappe.website.render.render("message", + http_status_code=http_status_code, fullpage=True) return response diff --git a/frappe/boot.py b/frappe/boot.py index 5d042f82ce..0f4039c596 100644 --- a/frappe/boot.py +++ b/frappe/boot.py @@ -236,6 +236,8 @@ def load_print(bootinfo, doclist): print_settings.doctype = ":Print Settings" doclist.append(print_settings) load_print_css(bootinfo, print_settings) + doclist.extend(frappe.get_all('Print Style', 'name', + dict(disabled=0), update=dict(doctype=':Print Style'))) def load_print_css(bootinfo, print_settings): import frappe.www.printview diff --git a/frappe/desk/page/setup_wizard/setup_wizard.css b/frappe/desk/page/setup_wizard/setup_wizard.css index 5313a6b4bc..f61ea87863 100644 --- a/frappe/desk/page/setup_wizard/setup_wizard.css +++ b/frappe/desk/page/setup_wizard/setup_wizard.css @@ -8,13 +8,9 @@ } @media (min-width: 768px) { - .setup-wizard-slide.single-column { + .setup-wizard-slide { max-width: 500px; } - - .setup-wizard-slide.two-column { - max-width: 768px; - } } .setup-wizard-slide .lead { @@ -45,7 +41,7 @@ } .setup-wizard-slide.with-form { - margin: 30px auto; + margin: 60px auto; padding: 10px 50px; border: 1px solid #d1d8dd; box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.1); @@ -145,7 +141,6 @@ cursor: pointer; } - .setup-wizard-message-image { margin: 15px auto; } diff --git a/frappe/modules/import_file.py b/frappe/modules/import_file.py index 9a2c080d9b..ade3614c8e 100644 --- a/frappe/modules/import_file.py +++ b/frappe/modules/import_file.py @@ -87,7 +87,8 @@ def read_doc_from_file(path): ignore_values = { "Report": ["disabled"], "Print Format": ["disabled"], - "Email Alert": ["enabled"] + "Email Alert": ["enabled"], + "Print Style": ["disabled"] } ignore_doctypes = [""] diff --git a/frappe/modules/utils.py b/frappe/modules/utils.py index 79933a60a5..9e43a28c6f 100644 --- a/frappe/modules/utils.py +++ b/frappe/modules/utils.py @@ -10,8 +10,9 @@ import frappe.utils from frappe import _ lower_case_files_for = ['DocType', 'Page', 'Report', - "Workflow", 'Module Def', 'Desktop Item', 'Workflow State', 'Workflow Action', 'Print Format', - "Website Theme", 'Web Form', 'Email Alert'] + "Workflow", 'Module Def', 'Desktop Item', 'Workflow State', + 'Workflow Action', 'Print Format', "Website Theme", 'Web Form', + 'Email Alert', 'Print Style'] def export_module_json(doc, is_standard, module): """Make a folder for the given doc and add its json file (make it a standard diff --git a/frappe/printing/doctype/print_settings/print_settings.json b/frappe/printing/doctype/print_settings/print_settings.json index b191ac663a..40bf15d18b 100644 --- a/frappe/printing/doctype/print_settings/print_settings.json +++ b/frappe/printing/doctype/print_settings/print_settings.json @@ -260,7 +260,7 @@ "columns": 0, "default": "Modern", "fieldname": "print_style", - "fieldtype": "Select", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -271,7 +271,7 @@ "label": "Print Style", "length": 0, "no_copy": 0, - "options": "Modern\nClassic\nStandard\nMonochrome", + "options": "Print Style", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -597,7 +597,7 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2017-05-03 05:58:55.562540", + "modified": "2017-08-17 02:15:55.025352", "modified_by": "Administrator", "module": "Printing", "name": "Print Settings", diff --git a/frappe/printing/doctype/print_settings/test_print_settings.js b/frappe/printing/doctype/print_settings/test_print_settings.js new file mode 100644 index 0000000000..af61095e97 --- /dev/null +++ b/frappe/printing/doctype/print_settings/test_print_settings.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Print Settings", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Print Settings + () => frappe.tests.make('Print Settings', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/frappe/printing/doctype/print_style/__init__.py b/frappe/printing/doctype/print_style/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/printing/doctype/print_style/print_style.js b/frappe/printing/doctype/print_style/print_style.js new file mode 100644 index 0000000000..3b50ba3038 --- /dev/null +++ b/frappe/printing/doctype/print_style/print_style.js @@ -0,0 +1,8 @@ +// Copyright (c) 2017, Frappe Technologies and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Print Style', { + refresh: function(frm) { + + } +}); diff --git a/frappe/printing/doctype/print_style/print_style.json b/frappe/printing/doctype/print_style/print_style.json new file mode 100644 index 0000000000..29e88a460a --- /dev/null +++ b/frappe/printing/doctype/print_style/print_style.json @@ -0,0 +1,214 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 1, + "autoname": "field:print_style_name", + "beta": 0, + "creation": "2017-08-17 01:25:56.910716", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "print_style_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Print Style Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_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": 1, + "in_standard_filter": 0, + "label": "Disabled", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "standard", + "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": "Standard", + "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": "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": "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": 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": "preview", + "fieldtype": "Attach Image", + "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": "Preview", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_field": "preview", + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2017-08-17 02:18:08.132853", + "modified_by": "Administrator", + "module": "Printing", + "name": "Print Style", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/frappe/printing/doctype/print_style/print_style.py b/frappe/printing/doctype/print_style/print_style.py new file mode 100644 index 0000000000..310babd5df --- /dev/null +++ b/frappe/printing/doctype/print_style/print_style.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, 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 PrintStyle(Document): + def validate(self): + if (self.standard==1 + and not frappe.local.conf.get("developer_mode") + and not (frappe.flags.in_import or frappe.flags.in_test)): + + frappe.throw(frappe._("Standard Print Style cannot be changed. Please duplicate to edit.")) + + def on_update(self): + self.export_doc() + + def export_doc(self): + # export + from frappe.modules.utils import export_module_json + export_module_json(self, self.standard == 1, 'Printing') diff --git a/frappe/printing/doctype/print_style/test_print_style.js b/frappe/printing/doctype/print_style/test_print_style.js new file mode 100644 index 0000000000..4fceaad65d --- /dev/null +++ b/frappe/printing/doctype/print_style/test_print_style.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Print Style", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Print Style + () => frappe.tests.make('Print Style', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/frappe/printing/doctype/print_style/test_print_style.py b/frappe/printing/doctype/print_style/test_print_style.py new file mode 100644 index 0000000000..cee57f8826 --- /dev/null +++ b/frappe/printing/doctype/print_style/test_print_style.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +class TestPrintStyle(unittest.TestCase): + pass diff --git a/frappe/printing/print_style/__init__.py b/frappe/printing/print_style/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/printing/print_style/classic/__init__.py b/frappe/printing/print_style/classic/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/printing/print_style/classic/classic.json b/frappe/printing/print_style/classic/classic.json new file mode 100644 index 0000000000..149bf6dc09 --- /dev/null +++ b/frappe/printing/print_style/classic/classic.json @@ -0,0 +1,14 @@ +{ + "creation": "2017-08-17 02:00:12.502887", + "css": "/*\n\tcommon style for whole page\n\tThis should include:\n\t+ page size related settings\n\t+ font family settings\n\t+ line spacing settings\n*/\n.print-format div,\n.print-format span,\n.print-format td,\n.print-format h1,\n.print-format h2,\n.print-format h3,\n.print-format h4 {\n\tfont-family: Georgia, serif;\n}\n", + "disabled": 0, + "docstatus": 0, + "doctype": "Print Style", + "idx": 1, + "modified": "2017-08-17 05:02:24.128436", + "modified_by": "Administrator", + "name": "Classic", + "owner": "Administrator", + "print_style_name": "Classic", + "standard": 1 +} \ No newline at end of file diff --git a/frappe/printing/print_style/modern/__init__.py b/frappe/printing/print_style/modern/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/printing/print_style/modern/modern.json b/frappe/printing/print_style/modern/modern.json new file mode 100644 index 0000000000..15822e6c2d --- /dev/null +++ b/frappe/printing/print_style/modern/modern.json @@ -0,0 +1,14 @@ +{ + "creation": "2017-08-17 02:16:58.060374", + "css": ".print-heading {\n\ttext-align: right;\n\ttext-transform: uppercase;\n\tcolor: #666;\n\tpadding-bottom: 20px;\n\tmargin-bottom: 20px;\n\tborder-bottom: 1px solid #d1d8dd;\n}\n\n.print-heading h2 {\n\tfont-size: 24px;\n}\n\n.print-format th {\n\tbackground-color: #eee !important;\n\tborder-bottom: 0px !important;\n}\n\n/* modern format: don't remove this line */", + "disabled": 0, + "docstatus": 0, + "doctype": "Print Style", + "idx": 0, + "modified": "2017-08-17 05:02:05.043839", + "modified_by": "Administrator", + "name": "Modern", + "owner": "Administrator", + "print_style_name": "Modern", + "standard": 1 +} \ No newline at end of file diff --git a/frappe/printing/print_style/monochrome/__init__.py b/frappe/printing/print_style/monochrome/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/printing/print_style/monochrome/monochrome.json b/frappe/printing/print_style/monochrome/monochrome.json new file mode 100644 index 0000000000..4e4c1b393e --- /dev/null +++ b/frappe/printing/print_style/monochrome/monochrome.json @@ -0,0 +1,14 @@ +{ + "creation": "2017-08-17 02:16:20.992989", + "css": ".print-format * {\n\tcolor: #000 !important;\n}\n\n.print-format .alert {\n\tbackground-color: inherit;\n\tborder: 1px dashed #333;\n}\n\n.print-format .table-bordered,\n.print-format .table-bordered > thead > tr > th,\n.print-format .table-bordered > tbody > tr > th,\n.print-format .table-bordered > tfoot > tr > th,\n.print-format .table-bordered > thead > tr > td,\n.print-format .table-bordered > tbody > tr > td,\n.print-format .table-bordered > tfoot > tr > td {\n\tborder: 1px solid #333;\n}\n\n.print-format hr {\n\tborder-top: 1px solid #333;\n}\n\n.print-heading {\n\tborder-bottom: 2px solid #333;\n}\n", + "disabled": 0, + "docstatus": 0, + "doctype": "Print Style", + "idx": 0, + "modified": "2017-08-17 05:02:14.874082", + "modified_by": "Administrator", + "name": "Monochrome", + "owner": "Administrator", + "print_style_name": "Monochrome", + "standard": 1 +} \ No newline at end of file diff --git a/frappe/public/css/form.css b/frappe/public/css/form.css index 00674934af..453266c2e0 100644 --- a/frappe/public/css/form.css +++ b/frappe/public/css/form.css @@ -11,6 +11,12 @@ padding: 10px 0px; border-bottom: 1px solid #d1d8dd; } +.print-toolbar > div { + padding-right: 0px; +} +.print-toolbar > div:last-child { + padding-right: 15px; +} .form-inner-toolbar { padding: 10px 15px 0px; background-color: #fafbfc; @@ -588,7 +594,8 @@ select.form-control { .password-strength-message { margin-top: -10px; } -.control-code { +.control-code, +.control-code.bold { height: 400px; font-family: Monaco, "Courier New", monospace; background-color: black; diff --git a/frappe/public/js/frappe/dom.js b/frappe/public/js/frappe/dom.js index f3727ae16f..0a3890df29 100644 --- a/frappe/public/js/frappe/dom.js +++ b/frappe/public/js/frappe/dom.js @@ -93,6 +93,7 @@ frappe.dom = { se.appendChild(document.createTextNode(txt)); } document.getElementsByTagName('head')[0].appendChild(se); + return se; }, add: function(parent, newtag, className, cs, innerHTML, onclick) { if(parent && parent.substr)parent = frappe.dom.by_id(parent); diff --git a/frappe/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index cc99eae370..c7b82482f0 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -35,7 +35,13 @@ frappe.ui.form.PrintPreview = Class.extend({ this.print_sel = this.wrapper .find(".print-preview-select") .on("change", function () { - me.multilingual_preview() + me.multilingual_preview(); + }); + + this.print_style_select = this.wrapper + .find('.print-style-select') + .on("change", function () { + me.multilingual_preview(); }); //On selection of language get code and pass it to preview method @@ -64,11 +70,13 @@ frappe.ui.form.PrintPreview = Class.extend({ this.wrapper.find(".btn-download-pdf").click(function () { if (!me.is_old_style()) { + let print_style = me.selected_style(); var w = window.open( 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() + + (print_style ? '&style=' + print_style : '') + "&no_letterhead=" + (me.with_letterhead() ? "0" : "1") + (me.lang_code ? ("&_lang=" + me.lang_code) : "")) ); @@ -79,7 +87,7 @@ frappe.ui.form.PrintPreview = Class.extend({ }); this.wrapper.find(".btn-print-edit").on("click", function () { - var print_format = me.get_print_format(); + let print_format = me.get_print_format(); if (print_format && print_format.name) { if (print_format.print_format_builder) { frappe.set_route("print-format-builder", print_format.name); @@ -147,11 +155,13 @@ frappe.ui.form.PrintPreview = Class.extend({ }, new_page_preview: function (printit) { var me = this; + let print_style = me.selected_style(); var w = window.open(frappe.urllib.get_full_url("/printview?" + "doctype=" + encodeURIComponent(me.frm.doc.doctype) + "&name=" + encodeURIComponent(me.frm.doc.name) + (printit ? "&trigger_print=1" : "") + "&format=" + me.selected_format() + + (print_style ? '&style=' + print_style : '') + "&no_letterhead=" + (me.with_letterhead() ? "0" : "1") + (me.lang_code ? ("&_lang=" + me.lang_code) : ""))); if (!w) { @@ -164,6 +174,7 @@ frappe.ui.form.PrintPreview = Class.extend({ args: { doc: this.frm.doc, print_format: this.selected_format(), + style: this.selected_style(), no_letterhead: !this.with_letterhead() ? 1 : 0, _lang: this.lang_code }, @@ -191,8 +202,11 @@ frappe.ui.form.PrintPreview = Class.extend({ }, refresh_print_options: function () { this.print_formats = frappe.meta.get_print_formats(this.frm.doctype); + this.print_style_select.empty() + .add_options([''].concat(Object.keys(locals[':Print Style'] || {}).sort())); return this.print_sel .empty().add_options(this.print_formats); + }, with_old_style: function (opts) { frappe.require("/assets/js/print_format_v3.min.js", function () { @@ -215,6 +229,9 @@ frappe.ui.form.PrintPreview = Class.extend({ selected_format: function () { return this.print_sel.val() || this.frm.meta.default_print_format || "Standard"; }, + selected_style: function () { + return this.print_style_select.val() || ''; + }, is_old_style: function (format) { return this.get_print_format(format).print_format_type === "Client"; }, @@ -233,6 +250,8 @@ frappe.ui.form.PrintPreview = Class.extend({ return this.print_letterhead.is(":checked") ? 1 : 0; }, set_style: function (style) { + $('#print-style').remove(); + console.log(style || frappe.boot.print_css); frappe.dom.set_style(style || frappe.boot.print_css, "print-style"); } }); diff --git a/frappe/public/js/frappe/form/templates/print_layout.html b/frappe/public/js/frappe/form/templates/print_layout.html index eac092f390..e5f25261ef 100644 --- a/frappe/public/js/frappe/form/templates/print_layout.html +++ b/frappe/public/js/frappe/form/templates/print_layout.html @@ -2,6 +2,8 @@ -
+
diff --git a/frappe/public/less/form.less b/frappe/public/less/form.less index e9c80cb84c..086527a605 100644 --- a/frappe/public/less/form.less +++ b/frappe/public/less/form.less @@ -14,6 +14,13 @@ margin: 0px; padding: 10px 0px; border-bottom: 1px solid @border-color; + + > div { + padding-right: 0px; + } + > div:last-child { + padding-right: 15px; + } } .form-inner-toolbar { @@ -735,7 +742,7 @@ select.form-control { margin-top: -10px; } -.control-code { +.control-code, .control-code.bold { height: 400px; font-family: Monaco, "Courier New", monospace; background-color: black; diff --git a/frappe/templates/styles/classic.css b/frappe/templates/styles/classic.css deleted file mode 100644 index b35e1044fd..0000000000 --- a/frappe/templates/styles/classic.css +++ /dev/null @@ -1,16 +0,0 @@ -/* - common style for whole page - This should include: - + page size related settings - + font family settings - + line spacing settings -*/ -.print-format div, -.print-format span, -.print-format td, -.print-format h1, -.print-format h2, -.print-format h3, -.print-format h4 { - font-family: serif; -} diff --git a/frappe/templates/styles/modern.css b/frappe/templates/styles/modern.css deleted file mode 100644 index 72b8c0cd71..0000000000 --- a/frappe/templates/styles/modern.css +++ /dev/null @@ -1,19 +0,0 @@ -.print-heading { - text-align: right; - text-transform: uppercase; - color: #666; - padding-bottom: 20px; - margin-bottom: 20px; - border-bottom: 1px solid #d1d8dd; -} - -.print-heading h2 { - font-size: 24px; -} - -.print-format th { - background-color: #eee !important; - border-bottom: 0px !important; -} - -/* modern format: don't remove this line */ \ No newline at end of file diff --git a/frappe/templates/styles/monochrome.css b/frappe/templates/styles/monochrome.css deleted file mode 100644 index 0e68c34e29..0000000000 --- a/frappe/templates/styles/monochrome.css +++ /dev/null @@ -1,26 +0,0 @@ -.print-format * { - color: #000 !important; -} - -.print-format .alert { - background-color: inherit; - border: 1px dashed #333; -} - -.print-format .table-bordered, -.print-format .table-bordered > thead > tr > th, -.print-format .table-bordered > tbody > tr > th, -.print-format .table-bordered > tfoot > tr > th, -.print-format .table-bordered > thead > tr > td, -.print-format .table-bordered > tbody > tr > td, -.print-format .table-bordered > tfoot > tr > td { - border: 1px solid #333; -} - -.print-format hr { - border-top: 1px solid #333; -} - -.print-heading { - border-bottom: 2px solid #333; -} diff --git a/frappe/website/render.py b/frappe/website/render.py index 8892d403a4..33e82efd18 100644 --- a/frappe/website/render.py +++ b/frappe/website/render.py @@ -279,7 +279,8 @@ def render_403(e, pathname): frappe.local.response['context'] = dict( indicator_color = 'red', primary_action = '/login', - primary_label = _('Login') + primary_label = _('Login'), + fullpage=True ) return render_page("message"), e.http_status_code diff --git a/frappe/www/404.html b/frappe/www/404.html index 0759721ae8..a57bc8ebb8 100644 --- a/frappe/www/404.html +++ b/frappe/www/404.html @@ -3,6 +3,18 @@ {%- block title -%}{{_("Not Found")}}{%- endblock -%} {% block page_content %} + +
{{_("Page Missing or Moved")}} diff --git a/frappe/www/printview.py b/frappe/www/printview.py index 1ed4ee3782..0c20bb0c25 100644 --- a/frappe/www/printview.py +++ b/frappe/www/printview.py @@ -7,7 +7,6 @@ import frappe, os, copy, json, re from frappe import _ from frappe.modules import get_doc_path -from jinja2 import TemplateNotFound from frappe.utils import cint, strip_html from markdown2 import markdown from six import string_types @@ -173,7 +172,7 @@ def convert_markdown(doc, meta): @frappe.whitelist() def get_html_and_style(doc, name=None, print_format=None, meta=None, - no_letterhead=None, trigger_print=False): + no_letterhead=None, trigger_print=False, style=None): """Returns `html` and `style` of print format, used in PDF etc""" if isinstance(doc, string_types) and isinstance(name, string_types): @@ -186,7 +185,7 @@ def get_html_and_style(doc, name=None, print_format=None, meta=None, return { "html": get_html(doc, name=name, print_format=print_format, meta=meta, no_letterhead=no_letterhead, trigger_print=trigger_print), - "style": get_print_style(print_format=print_format) + "style": get_print_style(style=style, print_format=print_format) } def validate_print_permission(doc): @@ -349,7 +348,7 @@ def get_print_style(style=None, print_format=None, for_legacy=False): print_settings = frappe.get_doc("Print Settings") if not style: - style = print_settings.print_style or "Standard" + style = print_settings.print_style or '' context = { "print_settings": print_settings, @@ -359,10 +358,8 @@ def get_print_style(style=None, print_format=None, for_legacy=False): css = frappe.get_template("templates/styles/standard.css").render(context) - try: - css += frappe.get_template("templates/styles/" + style.lower() + ".css").render(context) - except TemplateNotFound: - pass + if style and frappe.db.exists('Print Style', style): + css = css + '\n' + frappe.db.get_value('Print Style', style, 'css') # move @import to top for at_import in list(set(re.findall("(@import url\([^\)]+\)[;]?)", css))): From 4996771f8eca55aa4bea20082e9be1717f733e6b Mon Sep 17 00:00:00 2001 From: tunde Date: Thu, 17 Aug 2017 14:17:02 +0100 Subject: [PATCH 49/69] adds new function `is_disabled_field` --- frappe/tests/ui/data/test_lib.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frappe/tests/ui/data/test_lib.js b/frappe/tests/ui/data/test_lib.js index 772be7a3bf..7ad4300403 100644 --- a/frappe/tests/ui/data/test_lib.js +++ b/frappe/tests/ui/data/test_lib.js @@ -164,5 +164,12 @@ frappe.tests = { control.val(value).trigger('change'); return frappe.timeout(0.5); }, - + is_disabled_field: function(fieldname){ + let control = $(`.form-control[data-fieldname="${fieldname}"]:disabled`); + if(!control.length) { + throw `did not find any control with fieldname ${fieldname}`; + } else { + return true; + } + } }; \ No newline at end of file From a0e95877f6f1e40eba31c4d8d1c2933822c5a036 Mon Sep 17 00:00:00 2001 From: tunde Date: Thu, 17 Aug 2017 20:23:06 +0100 Subject: [PATCH 50/69] adds some jsdocs style function comments --- frappe/tests/ui/data/test_lib.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/frappe/tests/ui/data/test_lib.js b/frappe/tests/ui/data/test_lib.js index 7ad4300403..8698c5ae32 100644 --- a/frappe/tests/ui/data/test_lib.js +++ b/frappe/tests/ui/data/test_lib.js @@ -140,6 +140,12 @@ frappe.tests = { // Method to check the visibility of an element return $(`${tag}:contains("${text}")`).is(`:visible`); }, + /** + * Clicks a button on a form. + * @param {String} text - The button's text + * @return {frappe.timeout} + * @throws will throw an exception if a matching visible button is not found + */ click_button: function(text) { let element = $(`.btn:contains("${text}"):visible`); if(!element.length) { @@ -148,6 +154,12 @@ frappe.tests = { element.click(); return frappe.timeout(0.5); }, + /** + * Clicks a link on a form. + * @param {String} text - The text of the link to be clicked + * @return {frappe.timeout} + * @throws will throw an exception if a link with the given text is not found + */ click_link: function(text) { let element = $(`a:contains("${text}"):visible`); if(!element.length) { @@ -156,6 +168,13 @@ frappe.tests = { element.get(0).click(); return frappe.timeout(0.5); }, + /** + * Sets the given control to the value given. + * @param {String} fieldname - The Doctype's field name + * @param {String} value - The value the control should be changed to + * @return {frappe.timeout} + * @throws will throw an exception if the field is not found or is not visible + */ set_control: function(fieldname, value) { let control = $(`.form-control[data-fieldname="${fieldname}"]:visible`); if(!control.length) { @@ -164,6 +183,12 @@ frappe.tests = { control.val(value).trigger('change'); return frappe.timeout(0.5); }, + /** + * Checks if given field is disabled. + * @param {String} fieldname - The Doctype field name + * @return {Boolean} true if condition is met + * @throws will throw an exception if the field is not found or is not a form control + */ is_disabled_field: function(fieldname){ let control = $(`.form-control[data-fieldname="${fieldname}"]:disabled`); if(!control.length) { From 66d2bfe3185df664b55dbe257e8b209976efc411 Mon Sep 17 00:00:00 2001 From: tunde Date: Thu, 17 Aug 2017 22:22:34 +0100 Subject: [PATCH 51/69] split `me.user_tags` only if it is truthy --- frappe/public/js/frappe/ui/tags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/ui/tags.js b/frappe/public/js/frappe/ui/tags.js index ede40f50ee..4fef3135cf 100644 --- a/frappe/public/js/frappe/ui/tags.js +++ b/frappe/public/js/frappe/ui/tags.js @@ -25,7 +25,7 @@ frappe.ui.TagEditor = Class.extend({ method: 'frappe.desk.tags.add_tag', args: me.get_args(tag), callback: function(r) { - var user_tags = me.user_tags.split(","); + var user_tags = me.user_tags ? me.user_tags.split(",") : []; user_tags.push(tag) me.user_tags = user_tags.join(","); me.on_change && me.on_change(me.user_tags); From 1040eb9e47e0e7e794805ac11b8b76b9d827cecf Mon Sep 17 00:00:00 2001 From: tunde Date: Thu, 17 Aug 2017 22:58:38 +0100 Subject: [PATCH 52/69] in `make_tag`, extend doc._user_tags --- frappe/public/js/frappe/form/sidebar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/sidebar.js b/frappe/public/js/frappe/form/sidebar.js index 6da3c6f8d8..989bdfbca4 100644 --- a/frappe/public/js/frappe/form/sidebar.js +++ b/frappe/public/js/frappe/form/sidebar.js @@ -87,7 +87,7 @@ frappe.ui.form.Sidebar = Class.extend({ parent: this.sidebar.find(".tag-area"), frm: this.frm, on_change: function(user_tags) { - me.frm.doc._user_tags = user_tags; + me.frm.doc._user_tags += ("," + user_tags); } }); }, From 595b4a88be351c91df1ce2a1f141042ec0bede87 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 18 Aug 2017 09:26:13 +0530 Subject: [PATCH 53/69] [fix] no default print style --- .../print_settings/print_settings.json | 1177 ++++++++--------- 1 file changed, 588 insertions(+), 589 deletions(-) diff --git a/frappe/printing/doctype/print_settings/print_settings.json b/frappe/printing/doctype/print_settings/print_settings.json index 40bf15d18b..21a80ce1e1 100644 --- a/frappe/printing/doctype/print_settings/print_settings.json +++ b/frappe/printing/doctype/print_settings/print_settings.json @@ -1,636 +1,635 @@ { - "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_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_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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, - "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_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, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "description": "", - "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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_6", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_6", + "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": "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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_8", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_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_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_8", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "print_hide_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": "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, + "allow_bulk_edit": 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, "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": "2017-08-17 02:15:55.025352", - "modified_by": "Administrator", - "module": "Printing", - "name": "Print Settings", - "name_case": "", - "owner": "Administrator", + ], + "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": "2017-08-17 02:15:55.025352", + "modified_by": "Administrator", + "module": "Printing", + "name": "Print Settings", + "name_case": "", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 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, + "apply_user_permissions": 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, + ], + "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 } \ No newline at end of file From 81322b9b638e2b680858ec17d317a233d2b2ae64 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 18 Aug 2017 11:24:16 +0530 Subject: [PATCH 54/69] Show comments in report --- frappe/public/css/slickgrid.css | 3 +++ frappe/public/less/slickgrid.less | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/frappe/public/css/slickgrid.css b/frappe/public/css/slickgrid.css index 30d7133a2d..961da50b55 100644 --- a/frappe/public/css/slickgrid.css +++ b/frappe/public/css/slickgrid.css @@ -57,3 +57,6 @@ .frappe-rtl .slick-wrapper { direction: ltr; } +.slick-cell > span[data-field="_comments"] * { + display: inline-block; +} diff --git a/frappe/public/less/slickgrid.less b/frappe/public/less/slickgrid.less index 9368c9f1bc..20494421ba 100644 --- a/frappe/public/less/slickgrid.less +++ b/frappe/public/less/slickgrid.less @@ -63,4 +63,8 @@ .frappe-rtl .slick-wrapper { direction: ltr; +} + +.slick-cell > span[data-field="_comments"] * { + display: inline-block; } \ No newline at end of file From 7dedc69461bfcf7cba04284d8d19fdeded66fd51 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 18 Aug 2017 14:53:38 +0530 Subject: [PATCH 55/69] [print-style] sync, fix tests and remove selection --- frappe/app.py | 8 +- frappe/boot.py | 2 - frappe/config/setup.py | 7 +- frappe/model/sync.py | 5 +- .../doctype/print_format/test_print_format.py | 4 +- .../doctype/print_settings/print_settings.js | 11 +- .../print_settings/print_settings.json | 1180 +++++++++-------- .../doctype/print_style/print_style.js | 7 + .../doctype/print_style/test_print_style.js | 7 +- .../printing/print_style/classic/classic.json | 5 +- .../printing/print_style/modern/modern.json | 5 +- .../print_style/monochrome/monochrome.json | 3 +- frappe/public/js/frappe/desk.js | 2 +- frappe/public/js/frappe/form/print.js | 21 +- .../frappe/form/templates/print_layout.html | 11 +- frappe/public/js/frappe/list/list_renderer.js | 4 + .../print_formats/standard_macros.html | 3 +- 17 files changed, 647 insertions(+), 638 deletions(-) diff --git a/frappe/app.py b/frappe/app.py index 2cd714fa9f..6884aa26fa 100644 --- a/frappe/app.py +++ b/frappe/app.py @@ -150,13 +150,13 @@ def handle_exception(e): elif http_status_code==403: frappe.respond_as_web_page(_("Not Permitted"), _("You do not have enough permissions to complete the action"), - http_status_code=http_status_code, indicator_color='red', fullpage=True) + http_status_code=http_status_code, indicator_color='red') return_as_message = True elif http_status_code==404: frappe.respond_as_web_page(_("Not Found"), _("The resource you are looking for is not available"), - http_status_code=http_status_code, indicator_color='red', fullpage=True) + http_status_code=http_status_code, indicator_color='red') return_as_message = True else: @@ -166,7 +166,7 @@ def handle_exception(e): frappe.respond_as_web_page("Server Error", traceback, http_status_code=http_status_code, - indicator_color='red', fullpage=True) + indicator_color='red') return_as_message = True if e.__class__ == frappe.AuthenticationError: @@ -179,7 +179,7 @@ def handle_exception(e): if return_as_message: response = frappe.website.render.render("message", - http_status_code=http_status_code, fullpage=True) + http_status_code=http_status_code) return response diff --git a/frappe/boot.py b/frappe/boot.py index 0f4039c596..5d042f82ce 100644 --- a/frappe/boot.py +++ b/frappe/boot.py @@ -236,8 +236,6 @@ def load_print(bootinfo, doclist): print_settings.doctype = ":Print Settings" doclist.append(print_settings) load_print_css(bootinfo, print_settings) - doclist.extend(frappe.get_all('Print Style', 'name', - dict(disabled=0), update=dict(doctype=':Print Style'))) def load_print_css(bootinfo, print_settings): import frappe.www.printview diff --git a/frappe/config/setup.py b/frappe/config/setup.py index cd2f58fcc4..55ed2dbd9e 100644 --- a/frappe/config/setup.py +++ b/frappe/config/setup.py @@ -124,7 +124,7 @@ def get_data(): { "type": "doctype", "name": "Deleted Document", - "label": _("Deleted Documents"), + "label": _("Deleted Documents"), "description": _("Restore or permanently delete a document.") }, ] @@ -180,6 +180,11 @@ def get_data(): "name": "Print Format", "description": _("Customized HTML Templates for printing transactions.") }, + { + "type": "doctype", + "name": "Print Style", + "description": _("Stylesheets for Print Formats") + }, ] }, { diff --git a/frappe/model/sync.py b/frappe/model/sync.py index 72e80a9ecc..9c80a946a1 100644 --- a/frappe/model/sync.py +++ b/frappe/model/sync.py @@ -56,8 +56,9 @@ def sync_for(app_name, force=0, sync_everything = False, verbose=False, reset_pe def get_doc_files(files, start_path, force=0, sync_everything = False, verbose=False): """walk and sync all doctypes and pages""" - document_type = ['doctype', 'page', 'report', 'print_format', 'website_theme', 'web_form', 'email_alert'] - for doctype in document_type: + document_types = ['doctype', 'page', 'report', 'print_format', + 'website_theme', 'web_form', 'email_alert', 'print_style'] + for doctype in document_types: doctype_path = os.path.join(start_path, doctype) if os.path.exists(doctype_path): diff --git a/frappe/printing/doctype/print_format/test_print_format.py b/frappe/printing/doctype/print_format/test_print_format.py index a32070e97b..e8375ae5e7 100644 --- a/frappe/printing/doctype/print_format/test_print_format.py +++ b/frappe/printing/doctype/print_format/test_print_format.py @@ -23,8 +23,8 @@ class TestPrintFormat(unittest.TestCase): def test_print_user_modern(self): print_html = self.test_print_user("Modern") - self.assertTrue("/* modern format: don't remove this line */" in print_html) + self.assertTrue("/* modern format: for-test */" in print_html) def test_print_user_classic(self): print_html = self.test_print_user("Classic") - self.assertTrue("font-family: serif;" in print_html) + self.assertTrue("/* classic format: for-test */" in print_html) diff --git a/frappe/printing/doctype/print_settings/print_settings.js b/frappe/printing/doctype/print_settings/print_settings.js index 5840c6930d..ef552e6d30 100644 --- a/frappe/printing/doctype/print_settings/print_settings.js +++ b/frappe/printing/doctype/print_settings/print_settings.js @@ -2,8 +2,15 @@ // For license information, please see license.txt frappe.ui.form.on("Print Settings", "print_style", function (frm) { - frm.get_field("print_style_preview").html(''); + frappe.db.get_value('Print Style', frm.doc.print_style, 'preview').then((r) => { + if(r.message.preview) { + frm.get_field("print_style_preview").$wrapper.html( + ``); + } else { + frm.get_field("print_style_preview").$wrapper.html( + `

${__("No Preview")}

`); + } + }); }); frappe.ui.form.on("Print Settings", "onload", function (frm) { diff --git a/frappe/printing/doctype/print_settings/print_settings.json b/frappe/printing/doctype/print_settings/print_settings.json index 21a80ce1e1..7e1bfa6861 100644 --- a/frappe/printing/doctype/print_settings/print_settings.json +++ b/frappe/printing/doctype/print_settings/print_settings.json @@ -1,635 +1,639 @@ { - "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_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_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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, - "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_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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_10", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_6", - "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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_8", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_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_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, "unique": 0 - }, + }, { - "allow_bulk_edit": 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, + "allow_bulk_edit": 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, "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": "2017-08-17 02:15:55.025352", - "modified_by": "Administrator", - "module": "Printing", - "name": "Print Settings", - "name_case": "", - "owner": "Administrator", + ], + "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": "2017-08-18 01:04:26.692081", + "modified_by": "Administrator", + "module": "Printing", + "name": "Print Settings", + "name_case": "", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 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, + "apply_user_permissions": 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, + ], + "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 } \ No newline at end of file diff --git a/frappe/printing/doctype/print_style/print_style.js b/frappe/printing/doctype/print_style/print_style.js index 3b50ba3038..71e863efa7 100644 --- a/frappe/printing/doctype/print_style/print_style.js +++ b/frappe/printing/doctype/print_style/print_style.js @@ -3,6 +3,13 @@ frappe.ui.form.on('Print Style', { refresh: function(frm) { + /* update in local */ + if (!frm.is_new() && !locals[':Print Style'][frm.doc.name]) { + locals[':Print Style'][frm.doc.name] = frm.doc; + } + frm.add_custom_button(__('Print Settings'), () => { + frappe.set_route('Form', 'Print Settings'); + }) } }); diff --git a/frappe/printing/doctype/print_style/test_print_style.js b/frappe/printing/doctype/print_style/test_print_style.js index 4fceaad65d..d676a0c831 100644 --- a/frappe/printing/doctype/print_style/test_print_style.js +++ b/frappe/printing/doctype/print_style/test_print_style.js @@ -12,12 +12,9 @@ QUnit.test("test: Print Style", function (assert) { // insert a new Print Style () => frappe.tests.make('Print Style', [ // values to be set - {key: 'value'} + {print_style_name: 'Test Print Style'}, + {css: '/* some css value */'} ]), - () => { - assert.equal(cur_frm.doc.key, 'value'); - }, - () => done() ]); }); diff --git a/frappe/printing/print_style/classic/classic.json b/frappe/printing/print_style/classic/classic.json index 149bf6dc09..1ad609a498 100644 --- a/frappe/printing/print_style/classic/classic.json +++ b/frappe/printing/print_style/classic/classic.json @@ -1,14 +1,15 @@ { "creation": "2017-08-17 02:00:12.502887", - "css": "/*\n\tcommon style for whole page\n\tThis should include:\n\t+ page size related settings\n\t+ font family settings\n\t+ line spacing settings\n*/\n.print-format div,\n.print-format span,\n.print-format td,\n.print-format h1,\n.print-format h2,\n.print-format h3,\n.print-format h4 {\n\tfont-family: Georgia, serif;\n}\n", + "css": "/*\n\tcommon style for whole page\n\tThis should include:\n\t+ page size related settings\n\t+ font family settings\n\t+ line spacing settings\n*/\n.print-format div,\n.print-format span,\n.print-format td,\n.print-format h1,\n.print-format h2,\n.print-format h3,\n.print-format h4 {\n\tfont-family: Georgia, serif;\n}\n\n/* classic format: for-test */", "disabled": 0, "docstatus": 0, "doctype": "Print Style", "idx": 1, - "modified": "2017-08-17 05:02:24.128436", + "modified": "2017-08-18 00:43:48.675833", "modified_by": "Administrator", "name": "Classic", "owner": "Administrator", + "preview": "/assets/frappe/images/help/print-style-classic.png", "print_style_name": "Classic", "standard": 1 } \ No newline at end of file diff --git a/frappe/printing/print_style/modern/modern.json b/frappe/printing/print_style/modern/modern.json index 15822e6c2d..2d79ab6e62 100644 --- a/frappe/printing/print_style/modern/modern.json +++ b/frappe/printing/print_style/modern/modern.json @@ -1,14 +1,15 @@ { "creation": "2017-08-17 02:16:58.060374", - "css": ".print-heading {\n\ttext-align: right;\n\ttext-transform: uppercase;\n\tcolor: #666;\n\tpadding-bottom: 20px;\n\tmargin-bottom: 20px;\n\tborder-bottom: 1px solid #d1d8dd;\n}\n\n.print-heading h2 {\n\tfont-size: 24px;\n}\n\n.print-format th {\n\tbackground-color: #eee !important;\n\tborder-bottom: 0px !important;\n}\n\n/* modern format: don't remove this line */", + "css": ".print-heading {\n\ttext-align: right;\n\ttext-transform: uppercase;\n\tcolor: #666;\n\tpadding-bottom: 20px;\n\tmargin-bottom: 20px;\n\tborder-bottom: 1px solid #d1d8dd;\n}\n\n.print-heading h2 {\n\tfont-size: 24px;\n}\n\n.print-format th {\n\tbackground-color: #eee !important;\n\tborder-bottom: 0px !important;\n}\n\n/* modern format: for-test */", "disabled": 0, "docstatus": 0, "doctype": "Print Style", "idx": 0, - "modified": "2017-08-17 05:02:05.043839", + "modified": "2017-08-18 00:44:07.438147", "modified_by": "Administrator", "name": "Modern", "owner": "Administrator", + "preview": "/assets/frappe/images/help/print-style-modern.png", "print_style_name": "Modern", "standard": 1 } \ No newline at end of file diff --git a/frappe/printing/print_style/monochrome/monochrome.json b/frappe/printing/print_style/monochrome/monochrome.json index 4e4c1b393e..eb75bc7211 100644 --- a/frappe/printing/print_style/monochrome/monochrome.json +++ b/frappe/printing/print_style/monochrome/monochrome.json @@ -5,10 +5,11 @@ "docstatus": 0, "doctype": "Print Style", "idx": 0, - "modified": "2017-08-17 05:02:14.874082", + "modified": "2017-08-18 00:44:25.023898", "modified_by": "Administrator", "name": "Monochrome", "owner": "Administrator", + "preview": "/assets/frappe/images/help/print-style-monochrome.png", "print_style_name": "Monochrome", "standard": 1 } \ No newline at end of file diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index 308dae4357..f65fb9f2be 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -202,7 +202,7 @@ frappe.Application = Class.extend({ moment.tz.add(frappe.boot.timezone_info); } if(frappe.boot.print_css) { - frappe.dom.set_style(frappe.boot.print_css) + frappe.dom.set_style(frappe.boot.print_css, "print-style"); } frappe.user.name = frappe.boot.user.name; } else { diff --git a/frappe/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index c7b82482f0..da19c8bed8 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -38,12 +38,6 @@ frappe.ui.form.PrintPreview = Class.extend({ me.multilingual_preview(); }); - this.print_style_select = this.wrapper - .find('.print-style-select') - .on("change", function () { - me.multilingual_preview(); - }); - //On selection of language get code and pass it to preview method this.language_sel = this.wrapper .find(".languages") @@ -70,13 +64,11 @@ frappe.ui.form.PrintPreview = Class.extend({ this.wrapper.find(".btn-download-pdf").click(function () { if (!me.is_old_style()) { - let print_style = me.selected_style(); var w = window.open( 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() - + (print_style ? '&style=' + print_style : '') + "&no_letterhead=" + (me.with_letterhead() ? "0" : "1") + (me.lang_code ? ("&_lang=" + me.lang_code) : "")) ); @@ -114,7 +106,8 @@ frappe.ui.form.PrintPreview = Class.extend({ this.lang_code = this.frm.doc.language; // Load all languages in the field this.language_sel.empty() - .add_options(frappe.get_languages()) + .add_options([{value:'', label:__("Select Language...")}] + .concat(frappe.get_languages())) .val(this.lang_code); this.preview(); }, @@ -155,13 +148,11 @@ frappe.ui.form.PrintPreview = Class.extend({ }, new_page_preview: function (printit) { var me = this; - let print_style = me.selected_style(); var w = window.open(frappe.urllib.get_full_url("/printview?" + "doctype=" + encodeURIComponent(me.frm.doc.doctype) + "&name=" + encodeURIComponent(me.frm.doc.name) + (printit ? "&trigger_print=1" : "") + "&format=" + me.selected_format() - + (print_style ? '&style=' + print_style : '') + "&no_letterhead=" + (me.with_letterhead() ? "0" : "1") + (me.lang_code ? ("&_lang=" + me.lang_code) : ""))); if (!w) { @@ -174,7 +165,6 @@ frappe.ui.form.PrintPreview = Class.extend({ args: { doc: this.frm.doc, print_format: this.selected_format(), - style: this.selected_style(), no_letterhead: !this.with_letterhead() ? 1 : 0, _lang: this.lang_code }, @@ -202,8 +192,6 @@ frappe.ui.form.PrintPreview = Class.extend({ }, refresh_print_options: function () { this.print_formats = frappe.meta.get_print_formats(this.frm.doctype); - this.print_style_select.empty() - .add_options([''].concat(Object.keys(locals[':Print Style'] || {}).sort())); return this.print_sel .empty().add_options(this.print_formats); @@ -229,9 +217,6 @@ frappe.ui.form.PrintPreview = Class.extend({ selected_format: function () { return this.print_sel.val() || this.frm.meta.default_print_format || "Standard"; }, - selected_style: function () { - return this.print_style_select.val() || ''; - }, is_old_style: function (format) { return this.get_print_format(format).print_format_type === "Client"; }, @@ -250,8 +235,6 @@ frappe.ui.form.PrintPreview = Class.extend({ return this.print_letterhead.is(":checked") ? 1 : 0; }, set_style: function (style) { - $('#print-style').remove(); - console.log(style || frappe.boot.print_css); frappe.dom.set_style(style || frappe.boot.print_css, "print-style"); } }); diff --git a/frappe/public/js/frappe/form/templates/print_layout.html b/frappe/public/js/frappe/form/templates/print_layout.html index e5f25261ef..bbdf415b17 100644 --- a/frappe/public/js/frappe/form/templates/print_layout.html +++ b/frappe/public/js/frappe/form/templates/print_layout.html @@ -3,9 +3,8 @@
-
-
-
+
-
+
{%= __("Print") %} + + {%= __("Settings...") %} - {%= __("Customize") %} + {%= __("Customize...") %} {%= __("Full Page") %} diff --git a/frappe/public/js/frappe/list/list_renderer.js b/frappe/public/js/frappe/list/list_renderer.js index 394d7d3f16..00d02a9f85 100644 --- a/frappe/public/js/frappe/list/list_renderer.js +++ b/frappe/public/js/frappe/list/list_renderer.js @@ -108,6 +108,10 @@ frappe.views.ListRenderer = Class.extend({ add_field(this.meta.title_field); } + if (this.meta.image_field) { + add_field(this.meta.image_field); + } + // enabled / disabled if (frappe.meta.has_field(this.doctype, 'enabled')) { add_field('enabled'); } if (frappe.meta.has_field(this.doctype, 'disabled')) { add_field('disabled'); } diff --git a/frappe/templates/print_formats/standard_macros.html b/frappe/templates/print_formats/standard_macros.html index 6fb0ba3da5..2de9191cbe 100644 --- a/frappe/templates/print_formats/standard_macros.html +++ b/frappe/templates/print_formats/standard_macros.html @@ -61,8 +61,7 @@ data-fieldname="{{ df.fieldname }}" data-fieldtype="{{ df.fieldtype }}" {%- macro render_field_with_label(df, doc) -%}
-
+
{% if df.fieldtype not in ("Image","HTML","Check") and doc.get(df.fieldname) != None %} From e62de7b0e7e5af6ec11f85c9fb6d26dc6afc089d Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 18 Aug 2017 15:03:41 +0530 Subject: [PATCH 56/69] [minor] print_style.js --- frappe/printing/doctype/print_style/print_style.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/frappe/printing/doctype/print_style/print_style.js b/frappe/printing/doctype/print_style/print_style.js index 71e863efa7..44c4a528f4 100644 --- a/frappe/printing/doctype/print_style/print_style.js +++ b/frappe/printing/doctype/print_style/print_style.js @@ -3,11 +3,6 @@ frappe.ui.form.on('Print Style', { refresh: function(frm) { - /* update in local */ - if (!frm.is_new() && !locals[':Print Style'][frm.doc.name]) { - locals[':Print Style'][frm.doc.name] = frm.doc; - } - frm.add_custom_button(__('Print Settings'), () => { frappe.set_route('Form', 'Print Settings'); }) From df7fac641a669bab9abec023ceef1c9f9de56ade Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 18 Aug 2017 16:20:41 +0530 Subject: [PATCH 57/69] [fix] DateRange filter when language is not en --- frappe/public/js/frappe/form/control.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js index 70e6c8216c..a5facbadf8 100755 --- a/frappe/public/js/frappe/form/control.js +++ b/frappe/public/js/frappe/form/control.js @@ -953,8 +953,12 @@ frappe.ui.form.ControlDateRange = frappe.ui.form.ControlData.extend({ this.set_mandatory && this.set_mandatory(value); }, parse: function(value) { - if(value && (value.indexOf(',') !== -1 || value.indexOf('to') !== -1)) { - var vals = value.split(/[( to )(,)]/); + const to = __(to); + var re = new RegExp(`[( ${to} )]`); + value = value.replace(re, ','); + + if(value && value.includes(',')) { + var vals = value.split(','); var from_date = moment(frappe.datetime.user_to_obj(vals[0])).format('YYYY-MM-DD'); var to_date = moment(frappe.datetime.user_to_obj(vals[vals.length-1])).format('YYYY-MM-DD'); return [from_date, to_date]; From 54406fbc551338ac7841f388a18db202259e7465 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 18 Aug 2017 16:29:50 +0530 Subject: [PATCH 58/69] no need of regex --- frappe/public/js/frappe/form/control.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js index a5facbadf8..182a5adf74 100755 --- a/frappe/public/js/frappe/form/control.js +++ b/frappe/public/js/frappe/form/control.js @@ -953,9 +953,8 @@ frappe.ui.form.ControlDateRange = frappe.ui.form.ControlData.extend({ this.set_mandatory && this.set_mandatory(value); }, parse: function(value) { - const to = __(to); - var re = new RegExp(`[( ${to} )]`); - value = value.replace(re, ','); + const to = __('to'); + value = value.replace(` ${to} `, ','); if(value && value.includes(',')) { var vals = value.split(','); From d41ebe587f45779a98a79e1cae70bbdbfdf98815 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 18 Aug 2017 16:42:00 +0530 Subject: [PATCH 59/69] [fix] minor --- frappe/public/js/frappe/form/control.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js index 182a5adf74..549181618f 100755 --- a/frappe/public/js/frappe/form/control.js +++ b/frappe/public/js/frappe/form/control.js @@ -953,8 +953,9 @@ frappe.ui.form.ControlDateRange = frappe.ui.form.ControlData.extend({ this.set_mandatory && this.set_mandatory(value); }, parse: function(value) { - const to = __('to'); - value = value.replace(` ${to} `, ','); + // replace the separator (which can be in user language) with comma + const to = __('{0} to {1}').replace('{0}', '').replace('{1}', ''); + value = value.replace(to, ','); if(value && value.includes(',')) { var vals = value.split(','); From 341e71ae86dd2db15d9e27e477bfbe24f69d463c Mon Sep 17 00:00:00 2001 From: ci2014 Date: Fri, 18 Aug 2017 15:39:38 +0200 Subject: [PATCH 60/69] Update file.py There were problems with Image links from Facebook for example, because they have and need ?parameter1=abc¶meter2=def in their address. --- frappe/core/doctype/file/file.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index a27d183fe4..6dcc94fa5e 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -329,7 +329,12 @@ def setup_folder_path(filename, new_parent): def get_extension(filename, extn, content): mimetype = None + if extn: + # remove '?' char and parameters from extn if present + if '?' in extn: + extn = extn.split('?', 1)[0] + mimetype = mimetypes.guess_type(filename + "." + extn)[0] if mimetype is None or not mimetype.startswith("image/") and content: From 5e3db25edb2f20360d376e51fd38fa560c6aa288 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Sun, 20 Aug 2017 14:09:11 +0530 Subject: [PATCH 61/69] [fix] timeline.js --- frappe/public/js/frappe/views/communication.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js index 1bc4c1087a..85d0b4820f 100755 --- a/frappe/public/js/frappe/views/communication.js +++ b/frappe/public/js/frappe/views/communication.js @@ -502,7 +502,7 @@ frappe.views.CommunicationComposer = Class.extend({ } if (cur_frm) { // clear input - cur_frm.timeline.input.val(""); + cur_frm.timeline.input && cur_frm.timeline.input.val(""); cur_frm.reload_doc(); } From ae272c88c2fa0a587a774c4c956b57a62a8f7df0 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 22 Aug 2017 12:26:18 +0530 Subject: [PATCH 62/69] Remove meta and style tags from email communication --- frappe/public/js/frappe/views/communication.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js index 85d0b4820f..741f910114 100755 --- a/frappe/public/js/frappe/views/communication.js +++ b/frappe/public/js/frappe/views/communication.js @@ -560,6 +560,10 @@ frappe.views.CommunicationComposer = Class.extend({ if(last_email) { var last_email_content = last_email.original_comment || last_email.content; + last_email_content = last_email_content + .replace(/<meta[\s\S]*meta>/g, '') // remove tags + .replace(/<style[\s\S]*<\/style>/g, ''); // // remove