From ac41e46ed6feeb21e6533a878a16c8860cfb1dc0 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Sun, 13 Oct 2019 20:48:54 +0530 Subject: [PATCH 001/153] fix(Email): poplib.error_proto exception --- frappe/email/receive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/email/receive.py b/frappe/email/receive.py index ee7075b570..b8fde57a43 100644 --- a/frappe/email/receive.py +++ b/frappe/email/receive.py @@ -298,7 +298,7 @@ class EmailServer: "Connection timed out", ) for message in messages: - if message in strip(cstr(e.message)) or message in strip(cstr(getattr(e, 'strerror', ''))): + if message in strip(cstr(e)) or message in strip(cstr(getattr(e, 'strerror', ''))): return True return False From 369e4ff5782ef30d8e01506d4b3c58a1ec71d18f Mon Sep 17 00:00:00 2001 From: Himanshu Date: Tue, 29 Oct 2019 15:22:38 +0530 Subject: [PATCH 002/153] Patch(Tags): Check if column exists (#8682) * fix: tags patch * fix: auto_commit_on_many_writes * fix: check if tag exists * fix: check if tag or tag link exists * fix: check if column exists * fix: set autocommit false * fix: use ignore in insert query for bulk insert * fix: add option to ignore duplicates --- frappe/database/database.py | 5 +++-- frappe/patches.txt | 1 + frappe/patches/v12_0/setup_tags.py | 19 +++++++++++-------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index 95096ed2d9..1e6a85236e 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -968,7 +968,7 @@ class Database(object): frappe.flags.touched_tables = set() frappe.flags.touched_tables.update(tables) - def bulk_insert(self, doctype, fields, values): + def bulk_insert(self, doctype, fields, values, ignore_duplicates=False): """ Insert multiple records at a time @@ -982,7 +982,8 @@ class Database(object): for idx, value in enumerate(values): insert_list.append(tuple(value)) if idx and (idx%10000 == 0 or idx < len(values)-1): - self.sql("""INSERT INTO `tab{doctype}` ({fields}) VALUES {values}""".format( + self.sql("""INSERT {ignore_duplicates} INTO `tab{doctype}` ({fields}) VALUES {values}""".format( + ignore_duplicates="IGNORE" if ignore_duplicates else "", doctype=doctype, fields=fields, values=", ".join(['%s'] * len(insert_list)) diff --git a/frappe/patches.txt b/frappe/patches.txt index 8321debf3a..621a2107df 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -254,3 +254,4 @@ frappe.patches.v12_0.delete_duplicate_indexes frappe.patches.v12_0.set_default_incoming_email_port frappe.patches.v12_0.update_global_search execute:frappe.reload_doc('desk', 'doctype', 'notification_settings') +frappe.patches.v12_0.setup_tags diff --git a/frappe/patches/v12_0/setup_tags.py b/frappe/patches/v12_0/setup_tags.py index cd50b0d505..d663cb2e0e 100644 --- a/frappe/patches/v12_0/setup_tags.py +++ b/frappe/patches/v12_0/setup_tags.py @@ -12,19 +12,22 @@ def execute(): time = frappe.utils.get_datetime() for doctype in frappe.get_list("DocType", filters={"istable": 0, "issingle": 0}): - for dt_tags in frappe.db.sql("select `name`, `_user_tags` from `tab{0}`".format(doctype.name), as_dict=True): - tags = dt_tags.get("_user_tags").split(",") if dt_tags.get("_user_tags") else None - if not tags: + if not frappe.db.count(doctype.name) or not frappe.db.has_column(doctype.name, "_user_tags"): + continue + + for _user_tags in frappe.db.sql("select `name`, `_user_tags` from `tab{0}`".format(doctype.name), as_dict=True): + if not _user_tags.get("_user_tags"): continue - for tag in tags: + for tag in _user_tags.get("_user_tags").split(",") if _user_tags.get("_user_tags") else []: if not tag: continue tag_list.append((tag.strip(), time, time, 'Administrator')) - tag_link_name = frappe.generate_hash(dt_tags.name + tag.strip() + doctype.name, 10), - tag_links.append((tag_link_name, doctype.name, dt_tags.name, tag.strip(), time, time, 'Administrator')) + tag_link_name = frappe.generate_hash(_user_tags.name + tag.strip() + doctype.name, 10) + tag_links.append((tag_link_name, doctype.name, _user_tags.name, tag.strip(), time, time, 'Administrator')) - frappe.db.bulk_insert("Tag", fields=["name", "creation", "modified", "modified_by"], values=set(tag_list)) - frappe.db.bulk_insert("Tag Link", fields=["name", "document_type", "document_name", "tag", "creation", "modified", "modified_by"], values=set(tag_links)) \ No newline at end of file + + frappe.db.bulk_insert("Tag", fields=["name", "creation", "modified", "modified_by"], values=set(tag_list), ignore_duplicates=True) + frappe.db.bulk_insert("Tag Link", fields=["name", "document_type", "document_name", "tag", "creation", "modified", "modified_by"], values=set(tag_links), ignore_duplicates=True) From f185ed979088bf4e0906f721bc033f06c30dd7b9 Mon Sep 17 00:00:00 2001 From: Sahil Khan Date: Wed, 30 Oct 2019 13:09:26 +0550 Subject: [PATCH 003/153] bumped to version 12.0.18 --- frappe/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 6424dcd9b5..77207e017f 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -23,7 +23,7 @@ if sys.version[0] == '2': reload(sys) sys.setdefaultencoding("utf-8") -__version__ = '12.0.17' +__version__ = '12.0.18' __title__ = "Frappe Framework" local = Local() From 1b4c752959ca0e4f61bec24f6bc6c5566313c96f Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 6 Nov 2019 15:10:48 +0530 Subject: [PATCH 004/153] fix: Barcode Control - Fix render caching in forms - Handle raw and svg value --- .../public/js/frappe/form/controls/barcode.js | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/barcode.js b/frappe/public/js/frappe/form/controls/barcode.js index 1cd1411b49..8245962d7e 100644 --- a/frappe/public/js/frappe/form/controls/barcode.js +++ b/frappe/public/js/frappe/form/controls/barcode.js @@ -1,18 +1,27 @@ -import JsBarcode from "jsbarcode"; +import JsBarcode from 'jsbarcode'; frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({ make_wrapper() { // Create the elements for barcode area this._super(); + this.default_svg = ''; let $input_wrapper = this.$wrapper.find('.control-input-wrapper'); - this.barcode_area = $(`
`); + this.barcode_area = $( + `
${this.default_svg}
` + ); this.barcode_area.appendTo($input_wrapper); }, parse(value) { // Parse raw value - return value ? this.get_barcode_html(value) : ""; + if (value) { + if (value.startsWith(' Date: Wed, 6 Nov 2019 16:27:07 +0530 Subject: [PATCH 005/153] fix: add iframe tag to acceptable elements --- frappe/utils/html_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/html_utils.py b/frappe/utils/html_utils.py index 5f3a6b4338..e5513364b6 100644 --- a/frappe/utils/html_utils.py +++ b/frappe/utils/html_utils.py @@ -117,7 +117,7 @@ acceptable_elements = [ 'p', 'pre', 'progress', 'q', 's', 'samp', 'section', 'select', 'small', 'sound', 'source', 'spacer', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot', - 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video' + 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video', 'iframe' ] mathml_elements = [ From 63ab2ca2f031e81b864c2a821dc6e1f9ac9e0085 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 6 Nov 2019 16:32:12 +0530 Subject: [PATCH 006/153] fix: strip_html_tags from blog post content description --- frappe/website/doctype/blog_post/blog_post.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/website/doctype/blog_post/blog_post.py b/frappe/website/doctype/blog_post/blog_post.py index a6758b6b64..1b2fdf9a8c 100644 --- a/frappe/website/doctype/blog_post/blog_post.py +++ b/frappe/website/doctype/blog_post/blog_post.py @@ -61,7 +61,7 @@ class BlogPost(WebsiteGenerator): context.content = get_html_content_based_on_type(self, 'content', self.content_type) - context.description = self.blog_intro or context.content[:140] + context.description = self.blog_intro or strip_html_tags(context.content[:140]) context.metatags = { "name": self.title, From d3c73e3a89c7302152d3bee978d8c8d715e99768 Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 8 Nov 2019 12:34:18 +0530 Subject: [PATCH 007/153] fix: hide indicator on click even on page refresh --- .../notification_log/notification_log.json | 14 +++- .../notification_log/notification_log.py | 13 +++- .../frappe/ui/notifications/notifications.js | 75 +++++++++++++------ frappe/public/less/notifications.less | 13 +++- 4 files changed, 86 insertions(+), 29 deletions(-) diff --git a/frappe/desk/doctype/notification_log/notification_log.json b/frappe/desk/doctype/notification_log/notification_log.json index 32b66ef1ea..c49a6bd428 100644 --- a/frappe/desk/doctype/notification_log/notification_log.json +++ b/frappe/desk/doctype/notification_log/notification_log.json @@ -10,6 +10,7 @@ "email_content", "column_break_4", "document_type", + "read", "seen", "document_name", "from_user" @@ -62,7 +63,6 @@ "fieldname": "seen", "fieldtype": "Check", "hidden": 1, - "ignore_user_permissions": 1, "label": "Seen" }, { @@ -79,11 +79,19 @@ "options": "User", "read_only": 1, "search_index": 1 + }, + { + "default": "0", + "fieldname": "read", + "fieldtype": "Check", + "hidden": 1, + "ignore_user_permissions": 1, + "label": "Read" } ], "in_create": 1, - "modified": "2019-10-23 12:48:01.119356", - "modified_by": "Administrator", + "modified": "2019-11-07 20:42:07.548645", + "modified_by": "umair@erpnext.com", "module": "Desk", "name": "Notification Log", "owner": "Administrator", diff --git a/frappe/desk/doctype/notification_log/notification_log.py b/frappe/desk/doctype/notification_log/notification_log.py index 4efcaa558b..55d0f0f77a 100644 --- a/frappe/desk/doctype/notification_log/notification_log.py +++ b/frappe/desk/doctype/notification_log/notification_log.py @@ -112,9 +112,18 @@ def get_title_html(title): return '{0}'.format(title) @frappe.whitelist() -def mark_as_seen(docname): +def set_all_values_for_field(docnames, fieldname): + docnames = frappe.parse_json(docnames) + event_name = 'all_' + fieldname + if docnames: + filters = {'name': ['in', docnames]} + frappe.db.set_value('Notification Log', filters, fieldname, 1, update_modified=False) + frappe.publish_realtime(event_name, after_commit=True, user=frappe.session.user) + +@frappe.whitelist() +def mark_as_read(docname): if docname: - frappe.db.set_value('Notification Log', docname, 'seen', 1, update_modified=False) + frappe.db.set_value('Notification Log', docname, 'read', 1, update_modified=False) @frappe.whitelist() diff --git a/frappe/public/js/frappe/ui/notifications/notifications.js b/frappe/public/js/frappe/ui/notifications/notifications.js index 36d2891928..bce8e58fdf 100644 --- a/frappe/public/js/frappe/ui/notifications/notifications.js +++ b/frappe/public/js/frappe/ui/notifications/notifications.js @@ -212,26 +212,57 @@ frappe.ui.Notifications = class Notifications { } } - set_field_as_seen(docname, $el) { + set_field_as_read(docname, $el) { frappe.call( - 'frappe.desk.doctype.notification_log.notification_log.mark_as_seen', + 'frappe.desk.doctype.notification_log.notification_log.mark_as_read', { docname: docname } ).then(()=> { - $el.removeClass('unseen'); + $el.removeClass('unread'); }); } - explicitly_mark_as_seen(e, $target) { + explicitly_mark_as_read(e, $target) { e.preventDefault(); e.stopImmediatePropagation(); - let docname = $target.parents('.unseen').attr('data-name'); - this.set_field_as_seen(docname, $target.parents('.unseen')); + let docname = $target.parents('.unread').attr('data-name'); + this.set_field_as_read(docname, $target.parents('.unread')); } - mark_as_seen(e, $target) { + mark_as_read(e, $target) { let docname = $target.attr('data-name'); let df = this.dropdown_items.filter(f => docname.includes(f.name))[0]; - this.set_field_as_seen(df.name, $target); + this.set_field_as_read(df.name, $target); + } + + mark_all_as_read(e) { + e.stopImmediatePropagation(); + this.$dropdown_list.find('.unread').removeClass('unread'); + let unread_docnames = this.dropdown_items + .filter(item => item.read === 0) + .map(d => d.name); + if (!unread_docnames.length) return; + frappe.call( + 'frappe.desk.doctype.notification_log.notification_log.set_all_values_for_field', + { + docnames: unread_docnames, + fieldname: 'read' + } + ); + } + + mark_all_as_seen() { + this.$dropdown_list.find('.unseen').removeClass('unseen'); + let unseen_docnames = this.dropdown_items + .filter(item => item.seen === 0) + .map(d => d.name); + if (!unseen_docnames.length) return; + frappe.call( + 'frappe.desk.doctype.notification_log.notification_log.set_all_values_for_field', + { + docnames: unseen_docnames, + fieldname: 'seen' + } + ); } get_notifications_list(limit) { @@ -279,8 +310,9 @@ frappe.ui.Notifications = class Notifications { field.document_type, field.document_name ); + let read_class = field.read ? '' : 'unread'; let seen_class = field.seen ? '' : 'unseen'; - let mark_seen_action = field.seen ? '': 'data-action="mark_as_seen"'; + let mark_read_action = field.read ? '': 'data-action="mark_as_read"'; let message = field.subject; let title = message.match(/(.*?)<\/b>/); message = title ? message.replace(title[1], frappe.ellipsis(title[1], 100)): message; @@ -289,17 +321,17 @@ frappe.ui.Notifications = class Notifications { let user_avatar = frappe.avatar(user, 'avatar-small user-avatar'); let timestamp = frappe.datetime.comment_when(field.creation, true); let item_html = - ` ${user_avatar} ${message_html}
${timestamp}
-
`; @@ -333,6 +365,12 @@ frappe.ui.Notifications = class Notifications { ${__('Settings')} ` : ''; + let mark_all_read_html = + category.value === 'Notifications' + ? ` + ${__('Mark All as Read')} + ` + : ''; let html = `
  • ${settings_html} + ${mark_all_read_html}
  • @@ -418,22 +457,14 @@ frappe.ui.Notifications = class Notifications { }); this.$dropdown.on('hide.bs.dropdown', e => { let hide = $(e.currentTarget).data('closable'); - if (hide) { - this.$dropdown_list - .find('[data-category="Notifications"]') - .collapse('show'); - this.$dropdown_list - .find( - '[data-category="Todays Events"], [data-category="Open Documents"]' - ) - .collapse('hide'); - } $(e.currentTarget).data('closable', true); return hide; }); this.$dropdown.on('show.bs.dropdown', () => { + this.mark_all_as_seen(); if (this.$notification_indicator.is(':visible')) { + this.$notification_indicator.hide(); frappe.call( 'frappe.desk.doctype.notification_log.notification_log.trigger_indicator_hide' ); diff --git a/frappe/public/less/notifications.less b/frappe/public/less/notifications.less index 9c40a90a71..7a49709d16 100644 --- a/frappe/public/less/notifications.less +++ b/frappe/public/less/notifications.less @@ -7,6 +7,11 @@ cursor: pointer; } +.mark-all-read { + margin-top: 2px; + margin-right: 15px; +} + .notification-settings { margin-top: 2px; } @@ -35,6 +40,10 @@ margin-left: 150px; } +.navbar .dropdown-notifications .notifications-icon { + padding-top: 9px; +} + .notifications-indicator { font-size: 7px; position: absolute; @@ -64,7 +73,7 @@ a.recent-item:hover { background-color: #f0f4f7; } -a.unseen:hover .mark-read { +a.unread:hover .mark-read { display: inline-block; } @@ -89,7 +98,7 @@ a.unseen:hover .mark-read { font-weight: 500; } -.unseen { +.unread { background: @light-yellow; } From ab8d00a5b756aa290acf104e1f52c597dac011cf Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 8 Nov 2019 14:19:06 +0530 Subject: [PATCH 008/153] fix: make notification settings searchable --- .../notification_settings.json | 6 +-- .../frappe/ui/notifications/notifications.js | 37 +++++++++++++------ .../js/frappe/ui/toolbar/search_utils.js | 7 ++-- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/frappe/desk/doctype/notification_settings/notification_settings.json b/frappe/desk/doctype/notification_settings/notification_settings.json index 68eec92125..c2f3633d63 100644 --- a/frappe/desk/doctype/notification_settings/notification_settings.json +++ b/frappe/desk/doctype/notification_settings/notification_settings.json @@ -72,15 +72,14 @@ "fieldname": "user", "fieldtype": "Link", "hidden": 1, - "in_list_view": 1, "label": "User", "options": "User", "read_only": 1 } ], "in_create": 1, - "modified": "2019-10-23 12:42:56.175928", - "modified_by": "Administrator", + "modified": "2019-11-08 14:11:35.619306", + "modified_by": "frappetestuser2@gmail.com", "module": "Desk", "name": "Notification Settings", "owner": "Administrator", @@ -97,7 +96,6 @@ "write": 1 } ], - "read_only": 1, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 diff --git a/frappe/public/js/frappe/ui/notifications/notifications.js b/frappe/public/js/frappe/ui/notifications/notifications.js index bce8e58fdf..3ccbc3318c 100644 --- a/frappe/public/js/frappe/ui/notifications/notifications.js +++ b/frappe/public/js/frappe/ui/notifications/notifications.js @@ -1,3 +1,5 @@ +frappe.provide('frappe.search'); + frappe.ui.Notifications = class Notifications { constructor() { frappe.model @@ -29,10 +31,30 @@ frappe.ui.Notifications = class Notifications { ); frappe.utils.bind_actions_with_object(this.$dropdown_list, this); + let me = this; + frappe.search.utils.make_function_searchable( + me.route_to_settings, + __('Notification Settings'), + [this.notifications_settings], + ) + this.setup_notifications(); this.bind_events(); } + route_to_settings(settings_doc) { + let method = + 'frappe.desk.doctype.notification_settings.notification_settings.create_notification_settings'; + + return Promise.resolve() + .then(() => { + if (!settings_doc) return frappe.call(method); + }) + .then(() => { + frappe.set_route(`#Form/Notification Settings/${frappe.session.user}`); + }); + } + setup_notifications() { this.get_notifications_list(this.max_length).then(list => { this.dropdown_items = list; @@ -249,7 +271,7 @@ frappe.ui.Notifications = class Notifications { } ); } - + mark_all_as_seen() { this.$dropdown_list.find('.unseen').removeClass('unseen'); let unseen_docnames = this.dropdown_items @@ -368,7 +390,7 @@ frappe.ui.Notifications = class Notifications { let mark_all_read_html = category.value === 'Notifications' ? ` - ${__('Mark All as Read')} + ${__('Mark all as Read')} ` : ''; let html = `
  • @@ -407,16 +429,7 @@ frappe.ui.Notifications = class Notifications { e.stopImmediatePropagation(); this.$dropdown.removeClass('open'); this.$dropdown.trigger('hide.bs.dropdown'); - let method = - 'frappe.desk.doctype.notification_settings.notification_settings.create_notification_settings'; - - return Promise.resolve() - .then(() => { - if (!this.notifications_settings) return frappe.call(method); - }) - .then(() => { - frappe.set_route(`#Form/Notification Settings/${frappe.session.user}`); - }); + this.route_to_settings(this.notifications_settings); } bind_events() { diff --git a/frappe/public/js/frappe/ui/toolbar/search_utils.js b/frappe/public/js/frappe/ui/toolbar/search_utils.js index c67c4b0b13..153a4dfa67 100644 --- a/frappe/public/js/frappe/ui/toolbar/search_utils.js +++ b/frappe/public/js/frappe/ui/toolbar/search_utils.js @@ -622,20 +622,21 @@ frappe.search.utils = { value: this.bolden_match_part(__(item.label), txt), index: this.fuzzy_search(txt, target), match: item.label, - onclick: item.action, + onclick: () => item.action.apply(this, item.args) }); } }); return results; }, - make_function_searchable(_function, label=null) { + make_function_searchable(_function, label=null, args=null) { if (typeof _function !== 'function') { throw new Error('First argument should be a function'); } this.searchable_functions.push({ 'label': label || _function.name, - 'action': _function + 'action': _function, + 'args': args, }); }, searchable_functions: [], From bb46bb0fa72a687258f91658f7b57a1a6f55ac00 Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 8 Nov 2019 22:25:41 +0530 Subject: [PATCH 009/153] fix: codacy --- .../notification_log/notification_log.py | 18 +++++++-------- .../frappe/ui/notifications/notifications.js | 22 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/frappe/desk/doctype/notification_log/notification_log.py b/frappe/desk/doctype/notification_log/notification_log.py index 55d0f0f77a..96f1d5080a 100644 --- a/frappe/desk/doctype/notification_log/notification_log.py +++ b/frappe/desk/doctype/notification_log/notification_log.py @@ -54,13 +54,13 @@ def make_notification_logs(doc, users): if is_notifications_enabled(user): if doc.type == 'Energy Point' and not is_energy_point_enabled(): return - else: - _doc = frappe.new_doc('Notification Log') - _doc.update(doc) - _doc.for_user = user - _doc.subject = _doc.subject.replace('
    ', '').replace('
    ', '') - if _doc.for_user != _doc.from_user or doc.type == 'Energy Point': - _doc.insert(ignore_permissions=True) + + _doc = frappe.new_doc('Notification Log') + _doc.update(doc) + _doc.for_user = user + _doc.subject = _doc.subject.replace('
    ', '').replace('
    ', '') + if _doc.for_user != _doc.from_user or doc.type == 'Energy Point': + _doc.insert(ignore_permissions=True) def send_notification_email(doc): is_type_enabled = is_email_notifications_enabled_for_type(doc.for_user, doc.type) @@ -114,8 +114,8 @@ def get_title_html(title): @frappe.whitelist() def set_all_values_for_field(docnames, fieldname): docnames = frappe.parse_json(docnames) - event_name = 'all_' + fieldname - if docnames: + event_name = 'all_' + fieldname + if docnames: filters = {'name': ['in', docnames]} frappe.db.set_value('Notification Log', filters, fieldname, 1, update_modified=False) frappe.publish_realtime(event_name, after_commit=True, user=frappe.session.user) diff --git a/frappe/public/js/frappe/ui/notifications/notifications.js b/frappe/public/js/frappe/ui/notifications/notifications.js index 3ccbc3318c..0c41f19300 100644 --- a/frappe/public/js/frappe/ui/notifications/notifications.js +++ b/frappe/public/js/frappe/ui/notifications/notifications.js @@ -36,7 +36,7 @@ frappe.ui.Notifications = class Notifications { me.route_to_settings, __('Notification Settings'), [this.notifications_settings], - ) + ); this.setup_notifications(); this.bind_events(); @@ -47,12 +47,12 @@ frappe.ui.Notifications = class Notifications { 'frappe.desk.doctype.notification_settings.notification_settings.create_notification_settings'; return Promise.resolve() - .then(() => { - if (!settings_doc) return frappe.call(method); - }) - .then(() => { - frappe.set_route(`#Form/Notification Settings/${frappe.session.user}`); - }); + .then(() => { + if (!settings_doc) return frappe.call(method); + }) + .then(() => { + frappe.set_route(`#Form/Notification Settings/${frappe.session.user}`); + }); } setup_notifications() { @@ -389,10 +389,10 @@ frappe.ui.Notifications = class Notifications { : ''; let mark_all_read_html = category.value === 'Notifications' - ? ` - ${__('Mark all as Read')} - ` - : ''; + ? ` + ${__('Mark all as Read')} + ` + : ''; let html = `
  • Date: Tue, 12 Nov 2019 13:37:51 +0530 Subject: [PATCH 010/153] fix(Report): validate 'Script Manager' role only for report type 'Script Report' --- frappe/core/doctype/report/report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py index f71179d388..e88a2d3335 100644 --- a/frappe/core/doctype/report/report.py +++ b/frappe/core/doctype/report/report.py @@ -30,7 +30,7 @@ class Report(Document): if self.is_standard == "No": # allow only script manager to edit scripts - if frappe.session.user!="Administrator": + if self.report_type == 'Script Report' and frappe.conf.server_script_enabled and frappe.session.user != "Administrator": frappe.only_for('Script Manager', True) if frappe.db.get_value("Report", self.name, "is_standard") == "Yes": From 643f185edcb6d30edd3e6615852eaa0a4abb418e Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 12 Nov 2019 15:28:28 +0530 Subject: [PATCH 011/153] fix: track seen in notification settings --- .../notification_log/notification_log.json | 10 +----- .../notification_log/notification_log.py | 6 ++-- .../notification_settings.json | 14 ++++++-- .../notification_settings.py | 4 +++ .../frappe/ui/notifications/notifications.js | 32 ++++++++----------- 5 files changed, 32 insertions(+), 34 deletions(-) diff --git a/frappe/desk/doctype/notification_log/notification_log.json b/frappe/desk/doctype/notification_log/notification_log.json index c49a6bd428..ecb746df64 100644 --- a/frappe/desk/doctype/notification_log/notification_log.json +++ b/frappe/desk/doctype/notification_log/notification_log.json @@ -11,7 +11,6 @@ "column_break_4", "document_type", "read", - "seen", "document_name", "from_user" ], @@ -58,13 +57,6 @@ "read_only": 1, "search_index": 1 }, - { - "default": "0", - "fieldname": "seen", - "fieldtype": "Check", - "hidden": 1, - "label": "Seen" - }, { "fieldname": "document_name", "fieldtype": "Data", @@ -90,7 +82,7 @@ } ], "in_create": 1, - "modified": "2019-11-07 20:42:07.548645", + "modified": "2019-11-12 15:22:35.283678", "modified_by": "umair@erpnext.com", "module": "Desk", "name": "Notification Log", diff --git a/frappe/desk/doctype/notification_log/notification_log.py b/frappe/desk/doctype/notification_log/notification_log.py index 96f1d5080a..6f27fa4f44 100644 --- a/frappe/desk/doctype/notification_log/notification_log.py +++ b/frappe/desk/doctype/notification_log/notification_log.py @@ -112,13 +112,11 @@ def get_title_html(title): return '{0}'.format(title) @frappe.whitelist() -def set_all_values_for_field(docnames, fieldname): +def mark_all_as_read(docnames): docnames = frappe.parse_json(docnames) - event_name = 'all_' + fieldname if docnames: filters = {'name': ['in', docnames]} - frappe.db.set_value('Notification Log', filters, fieldname, 1, update_modified=False) - frappe.publish_realtime(event_name, after_commit=True, user=frappe.session.user) + frappe.db.set_value('Notification Log', filters, 'read', 1, update_modified=False) @frappe.whitelist() def mark_as_read(docname): diff --git a/frappe/desk/doctype/notification_settings/notification_settings.json b/frappe/desk/doctype/notification_settings/notification_settings.json index c2f3633d63..a162105299 100644 --- a/frappe/desk/doctype/notification_settings/notification_settings.json +++ b/frappe/desk/doctype/notification_settings/notification_settings.json @@ -13,7 +13,8 @@ "enable_email_assignment", "enable_email_energy_point", "enable_email_share", - "user" + "user", + "seen" ], "fields": [ { @@ -75,11 +76,18 @@ "label": "User", "options": "User", "read_only": 1 + }, + { + "default": "0", + "fieldname": "seen", + "fieldtype": "Check", + "hidden": 1, + "label": "Seen" } ], "in_create": 1, - "modified": "2019-11-08 14:11:35.619306", - "modified_by": "frappetestuser2@gmail.com", + "modified": "2019-11-12 14:50:16.822761", + "modified_by": "Administrator", "module": "Desk", "name": "Notification Settings", "owner": "Administrator", diff --git a/frappe/desk/doctype/notification_settings/notification_settings.py b/frappe/desk/doctype/notification_settings/notification_settings.py index 3bb3cf9320..1ac4e2b1dd 100644 --- a/frappe/desk/doctype/notification_settings/notification_settings.py +++ b/frappe/desk/doctype/notification_settings/notification_settings.py @@ -60,3 +60,7 @@ def get_permission_query_conditions(user): if not user: user = frappe.session.user return '''(`tabNotification Settings`.user = '{user}')'''.format(user=user) + +@frappe.whitelist() +def set_seen_value(value): + frappe.db.set_value('Notification Settings', frappe.session.user, 'seen', value, update_modified=False) \ No newline at end of file diff --git a/frappe/public/js/frappe/ui/notifications/notifications.js b/frappe/public/js/frappe/ui/notifications/notifications.js index 0c41f19300..c2e6ccaa81 100644 --- a/frappe/public/js/frappe/ui/notifications/notifications.js +++ b/frappe/public/js/frappe/ui/notifications/notifications.js @@ -59,8 +59,7 @@ frappe.ui.Notifications = class Notifications { this.get_notifications_list(this.max_length).then(list => { this.dropdown_items = list; this.render_notifications_dropdown(); - - if (this.$notifications.find('.unseen').length) { + if (this.notifications_settings.seen == 0) { this.$notification_indicator.show(); } }); @@ -264,26 +263,17 @@ frappe.ui.Notifications = class Notifications { .map(d => d.name); if (!unread_docnames.length) return; frappe.call( - 'frappe.desk.doctype.notification_log.notification_log.set_all_values_for_field', + 'frappe.desk.doctype.notification_log.notification_log.mark_all_as_read', { docnames: unread_docnames, - fieldname: 'read' } ); } - mark_all_as_seen() { - this.$dropdown_list.find('.unseen').removeClass('unseen'); - let unseen_docnames = this.dropdown_items - .filter(item => item.seen === 0) - .map(d => d.name); - if (!unseen_docnames.length) return; + mark_as_seen() { frappe.call( - 'frappe.desk.doctype.notification_log.notification_log.set_all_values_for_field', - { - docnames: unseen_docnames, - fieldname: 'seen' - } + 'frappe.desk.doctype.notification_settings.notification_settings.set_seen_value', + { value: 1 } ); } @@ -333,7 +323,6 @@ frappe.ui.Notifications = class Notifications { field.document_name ); let read_class = field.read ? '' : 'unread'; - let seen_class = field.seen ? '' : 'unseen'; let mark_read_action = field.read ? '': 'data-action="mark_as_read"'; let message = field.subject; let title = message.match(/(.*?)<\/b>/); @@ -343,7 +332,7 @@ frappe.ui.Notifications = class Notifications { let user_avatar = frappe.avatar(user, 'avatar-small user-avatar'); let timestamp = frappe.datetime.comment_when(field.creation, true); let item_html = - ` { + if (this.notifications_settings.seen == 1) { + this.notifications_settings.seen = 0; + frappe.call( + 'frappe.desk.doctype.notification_settings.notification_settings.set_seen_value', + { value: 0 } + ); + } this.$dropdown.find('.notifications-indicator').show(); this.update_dropdown(); }); @@ -475,7 +471,7 @@ frappe.ui.Notifications = class Notifications { }); this.$dropdown.on('show.bs.dropdown', () => { - this.mark_all_as_seen(); + this.mark_as_seen(); if (this.$notification_indicator.is(':visible')) { this.$notification_indicator.hide(); frappe.call( From 6d85f1215fb175231258f63156fef0482fb1a3f6 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Tue, 12 Nov 2019 17:36:59 +0530 Subject: [PATCH 012/153] fix: formatting for chart tooltip --- .../doctype/razorpay_settings/razorpay_settings.py | 1 - frappe/public/js/frappe/views/reports/report_view.js | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py index 26e0de35b5..c6ef12ff08 100644 --- a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py +++ b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py @@ -242,7 +242,6 @@ class RazorpaySettings(Document): redirect_to = data.get('redirect_to') or None redirect_message = data.get('redirect_message') or None - if self.flags.status_changed_to in ("Authorized", "Verified", "Completed"): if self.data.reference_doctype and self.data.reference_docname: custom_redirect_to = None diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js index 6503f1c7ac..b65402e6fe 100644 --- a/frappe/public/js/frappe/views/reports/report_view.js +++ b/frappe/public/js/frappe/views/reports/report_view.js @@ -500,10 +500,11 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { axisOptions: { shortenYAxisNumbers: 1 }, - - format_tooltip_x: value => value.doc.name, - format_tooltip_y: - value => frappe.format(value, get_df(value.field), { always_show_decimals: true, inline: true }, get_doc(value.doc)) + tooltipOptions: { + formatTooltipY: value => { + return frappe.format(value, get_df(this.chart_args.y_axes[0]), { always_show_decimals: true, inline: true }, get_doc(value.doc)) + } + } }); } From 4835c87c3fe9a28647fcc011c978dc2d02430684 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Tue, 12 Nov 2019 17:53:26 +0530 Subject: [PATCH 013/153] refactor: code styling --- frappe/public/js/frappe/views/reports/report_view.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js index b65402e6fe..7f6e24595a 100644 --- a/frappe/public/js/frappe/views/reports/report_view.js +++ b/frappe/public/js/frappe/views/reports/report_view.js @@ -501,9 +501,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { shortenYAxisNumbers: 1 }, tooltipOptions: { - formatTooltipY: value => { - return frappe.format(value, get_df(this.chart_args.y_axes[0]), { always_show_decimals: true, inline: true }, get_doc(value.doc)) - } + formatTooltipY: value => frappe.format(value, get_df(this.chart_args.y_axes[0]), { always_show_decimals: true, inline: true }, get_doc(value.doc)) } }); } From e36ad8d8defb4d8cd47a29ef9781e79cd210a6f8 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Tue, 12 Nov 2019 18:54:13 +0530 Subject: [PATCH 014/153] fix: filtering for blog category --- frappe/website/doctype/blog_post/blog_post.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/website/doctype/blog_post/blog_post.py b/frappe/website/doctype/blog_post/blog_post.py index a6758b6b64..5d0b47d338 100644 --- a/frappe/website/doctype/blog_post/blog_post.py +++ b/frappe/website/doctype/blog_post/blog_post.py @@ -145,11 +145,12 @@ def get_blog_category(route): def get_blog_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by=None): conditions = [] + category = filters.blog_category or sanitize_html(frappe.local.form_dict.blog_category or frappe.local.form_dict.category) if filters: if filters.blogger: conditions.append('t1.blogger=%s' % frappe.db.escape(filters.blogger)) - if filters.blog_category: - conditions.append('t1.blog_category=%s' % frappe.db.escape(filters.blog_category)) + if category: + conditions.append('t1.blog_category=%s' % frappe.db.escape(category)) if txt: conditions.append('(t1.content like {0} or t1.title like {0}")'.format(frappe.db.escape('%' + txt + '%'))) From eae67eb0ddb74ab97e9e9ebee2026a5737daa573 Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 12 Nov 2019 19:06:43 +0530 Subject: [PATCH 015/153] fix: set first option as value for 'is' condition if no value selected --- frappe/public/js/frappe/ui/filters/filter.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frappe/public/js/frappe/ui/filters/filter.js b/frappe/public/js/frappe/ui/filters/filter.js index 7923d57ad4..e163feb791 100644 --- a/frappe/public/js/frappe/ui/filters/filter.js +++ b/frappe/public/js/frappe/ui/filters/filter.js @@ -372,6 +372,10 @@ frappe.ui.filter_utils = { val = strip(val); } + if(condition == 'is' && !val) { + val = field.df.options[0].value; + } + if(field.df.original_type == 'Check') { val = (val=='Yes' ? 1 :0); } From b80b4a64dfbdf5f159a3ed85ab7319fc0694f912 Mon Sep 17 00:00:00 2001 From: Nickesh Date: Tue, 12 Nov 2019 19:08:16 +0530 Subject: [PATCH 016/153] Web form allow edit and new fix --- frappe/public/js/frappe/web_form/webform_script.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/web_form/webform_script.js b/frappe/public/js/frappe/web_form/webform_script.js index faae88fce6..d3b4021360 100644 --- a/frappe/public/js/frappe/web_form/webform_script.js +++ b/frappe/public/js/frappe/web_form/webform_script.js @@ -52,9 +52,10 @@ frappe.ready(function() { const data = setup_fields(r.message); let web_form_doc = data.web_form; - if (web_form_doc.doc_name && web_form_doc.allow_edit === 0) { - window.location.replace(window.location.pathname + "?new=1"); - return; + if (web_form_doc.name && web_form_doc.allow_edit === 0) { + if(!window.location.href.includes("?new=1")){ + window.location.replace(window.location.pathname + "?new=1"); + } } let doc = r.message.doc || build_doc(r.message); web_form.prepare(web_form_doc, doc); From f6b4fdef0caca5cc777085841b0d24bba8af1fe2 Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 12 Nov 2019 21:21:12 +0530 Subject: [PATCH 017/153] fix: codacy --- frappe/public/js/frappe/ui/filters/filter.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frappe/public/js/frappe/ui/filters/filter.js b/frappe/public/js/frappe/ui/filters/filter.js index e163feb791..212547a549 100644 --- a/frappe/public/js/frappe/ui/filters/filter.js +++ b/frappe/public/js/frappe/ui/filters/filter.js @@ -368,28 +368,28 @@ frappe.ui.filter_utils = { get_selected_value(field, condition) { let val = field.get_value(); - if(typeof val==='string') { + if (typeof val === 'string') { val = strip(val); } - if(condition == 'is' && !val) { + if (condition == 'is' && !val) { val = field.df.options[0].value; } - if(field.df.original_type == 'Check') { + if (field.df.original_type == 'Check') { val = (val=='Yes' ? 1 :0); } - if(condition.indexOf('like', 'not like')!==-1) { + if (condition.indexOf('like', 'not like') !== -1) { // automatically append wildcards - if(val && !(val.startsWith('%') || val.endsWith('%'))) { + if (val && !(val.startsWith('%') || val.endsWith('%'))) { val = '%' + val + '%'; } - } else if(in_list(["in", "not in"], condition)) { - if(val) { + } else if (in_list(["in", "not in"], condition)) { + if (val) { val = val.split(',').map(v => strip(v)); } - } if(val === '%') { + } if (val === '%') { val = ""; } From a7fb0dba577fbd5b7c11fc6c75ffef327ea32930 Mon Sep 17 00:00:00 2001 From: prssanna Date: Wed, 13 Nov 2019 11:48:20 +0530 Subject: [PATCH 018/153] fix(List): save checked rows on auto refresh --- frappe/public/js/frappe/list/list_view.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 6912065e1c..a1fe886484 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -1077,10 +1077,20 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { }); this.toggle_result_area(); this.render_list(); + if (this.$checks.length) { + this.set_rows_as_checked(); + } }); }); } + set_rows_as_checked() { + $.each(this.$checks, (i, el) => { + let docname = $(el).attr('data-name'); + this.$result.find(`.list-row-checkbox[data-name='${docname}']`).click(); + }); + } + on_row_checked() { this.$list_head_subject = this.$list_head_subject || this.$result.find('header .list-header-subject'); this.$checkbox_actions = this.$checkbox_actions || this.$result.find('header .checkbox-actions'); From e35af962571bd27b5270d1b664d188f36a44bf6f Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 13 Nov 2019 12:01:31 +0530 Subject: [PATCH 019/153] fix(scheduler): Activate scheduler if found inactive --- frappe/public/js/frappe/desk.js | 6 +----- frappe/utils/scheduler.py | 7 +++++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index 3deeb02ae4..4fbea6684f 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -136,11 +136,7 @@ frappe.Application = Class.extend({ method: 'frappe.core.page.background_jobs.background_jobs.get_scheduler_status', callback: function(r) { if (r.message[0] == __("Inactive")) { - frappe.msgprint({ - title: __("Scheduler Inactive"), - indicator: "red", - message: __("Background jobs are not running. Please contact Administrator") - }); + frappe.call('frappe.utils.scheduler.activate_scheduler'); } } }); diff --git a/frappe/utils/scheduler.py b/frappe/utils/scheduler.py index 68c3bc58a8..b46036d996 100755 --- a/frappe/utils/scheduler.py +++ b/frappe/utils/scheduler.py @@ -337,3 +337,10 @@ def get_last_active(): WHERE `user_type` = 'System User' AND `name` NOT IN ({standard_users})""" .format(standard_users=", ".join(["%s"]*len(STANDARD_USERS))), STANDARD_USERS)[0][0] + +@frappe.whitelist() +def activate_scheduler(): + if is_scheduler_disabled(): + enable_scheduler() + if frappe.conf.pause_scheduler: + update_site_config('pause_scheduler', 0) From e86aff147ac0cf4accb74216cc5d6f422cbb2a0a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2019 06:46:56 +0000 Subject: [PATCH 020/153] chore(deps): [security] bump tar from 2.2.1 to 2.2.2 Bumps [tar](https://github.com/npm/node-tar) from 2.2.1 to 2.2.2. **This update includes a security fix.** - [Release notes](https://github.com/npm/node-tar/releases) - [Commits](https://github.com/npm/node-tar/compare/v2.2.1...v2.2.2) Signed-off-by: dependabot-preview[bot] --- yarn.lock | 255 +++++++++++++++++++++++++++++------------------------- 1 file changed, 136 insertions(+), 119 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0838f3f255..7a59102a1e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -255,12 +255,17 @@ ansi-regex@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= -ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -628,10 +633,10 @@ camelcase@^3.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== caniuse-api@^3.0.0: version "3.0.0" @@ -738,14 +743,14 @@ cliui@^3.2.0: strip-ansi "^3.0.1" wrap-ansi "^2.0.0" -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" clone@^2.1.1, clone@^2.1.2: version "2.1.2" @@ -953,15 +958,6 @@ cross-spawn@^3.0.0: lru-cache "^4.0.1" which "^1.2.9" -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -1253,7 +1249,7 @@ debug@~4.1.0: dependencies: ms "^2.1.1" -decamelize@^1.1.1, decamelize@^1.1.2: +decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -1373,6 +1369,11 @@ elegant-spinner@^1.0.1: resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4= +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -1516,19 +1517,6 @@ execa@0.10.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - executable@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" @@ -1722,12 +1710,12 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== dependencies: - locate-path "^2.0.0" + locate-path "^3.0.0" for-in@^1.0.2: version "1.0.2" @@ -1803,7 +1791,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fstream@^1.0.0, fstream@^1.0.2: +fstream@^1.0.0, fstream@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== @@ -1856,6 +1844,11 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-pixels@^3.2.3: version "3.3.2" resolved "https://registry.yarnpkg.com/get-pixels/-/get-pixels-3.3.2.tgz#3f62fb8811932c69f262bba07cba72b692b4ff03" @@ -1942,9 +1935,9 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@~7.1.1: path-is-absolute "^1.0.0" glob@^7.1.3: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -1989,7 +1982,12 @@ globule@^1.0.0: lodash "~4.17.10" minimatch "~3.0.2" -graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@^4.1.2: + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== + +graceful-fs@^4.1.6: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== @@ -2249,7 +2247,12 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.3: +inherits@2, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= @@ -2766,12 +2769,12 @@ loader-utils@^0.2.16: json5 "^0.5.0" object-assign "^4.0.1" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== dependencies: - p-locate "^2.0.0" + p-locate "^3.0.0" path-exists "^3.0.0" lodash.camelcase@^4.3.0: @@ -2900,13 +2903,6 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -mem@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= - dependencies: - mimic-fn "^1.0.0" - meow@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" @@ -3000,11 +2996,6 @@ mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -3347,15 +3338,6 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" - os-tmpdir@^1.0.0, os-tmpdir@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -3374,19 +3356,19 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== +p-limit@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== dependencies: - p-try "^1.0.0" + p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== dependencies: - p-limit "^1.1.0" + p-limit "^2.0.0" p-map@^1.1.1: version "1.2.0" @@ -3398,10 +3380,10 @@ p-queue@^2.4.2: resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-2.4.2.tgz#03609826682b743be9a22dba25051bd46724fc34" integrity sha512-n8/y+yDJwBjoLQe1GSJbbaYQLTI7QHNZI2+rpmCDbe++WLf9HC3gf6iqj5yfPAV71W4UF3ql5W1+UBPXoXTxng== -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== parchment@quilljs/parchment#487850f7eb030a6c4e750ba809e58b09444e0bdb: version "2.0.0-dev" @@ -4283,6 +4265,11 @@ require-main-filename@^1.0.1: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + reserved-words@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/reserved-words/-/reserved-words-0.1.2.tgz#00a0940f98cd501aeaaac316411d9adc52b31ab1" @@ -4337,9 +4324,9 @@ rgba-regex@^1.0.0: integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= rimraf@2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: glob "^7.1.3" @@ -4572,12 +4559,12 @@ shebang-regex@^1.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= -showdown@^1.8.6: - version "1.9.0" - resolved "https://registry.yarnpkg.com/showdown/-/showdown-1.9.0.tgz#d49d2a0b6db21b7c2e96ef855f7b3b2a28ef46f4" - integrity sha512-x7xDCRIaOlicbC57nMhGfKamu+ghwsdVkHMttyn+DelwzuHOx4OHCVL/UW/2QOLH7BxfCcCCVVUix3boKXJKXQ== +showdown@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/showdown/-/showdown-1.9.1.tgz#134e148e75cd4623e09c21b0511977d79b5ad0ef" + integrity sha512-9cGuS382HcvExtf5AHk7Cb4pAeQQ+h0eTr33V1mu+crYWV4KvWAw6el92bDrqGEk5d46Ai/fhbEUwqJ/mTCNEA== dependencies: - yargs "^10.0.3" + yargs "^14.2" signal-exit@^3.0.0: version "3.0.2" @@ -4825,7 +4812,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2": version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -4833,6 +4820,15 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -4854,6 +4850,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -4962,12 +4965,12 @@ symbol-observable@1.0.1: integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= tar@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= + version "2.2.2" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" + integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== dependencies: block-stream "*" - fstream "^1.0.2" + fstream "^1.0.12" inherits "2" terser@^3.14.1: @@ -5296,6 +5299,15 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -5318,11 +5330,24 @@ y18n@^3.2.1: resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= +yargs-parser@^15.0.0: + version "15.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-15.0.0.tgz#cdd7a97490ec836195f59f3f4dbe5ea9e8f75f08" + integrity sha512-xLTUnCMc4JhxrPEPUYD5IBR1mWCK/aT6+RJ/K29JY2y1vD+FhtgKK0AXRWvI262q3QSffAQuTouFIKUuHX89wQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" @@ -5330,30 +5355,22 @@ yargs-parser@^5.0.0: dependencies: camelcase "^3.0.0" -yargs-parser@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" - integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ== +yargs@^14.2: + version "14.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.2.0.tgz#f116a9242c4ed8668790b40759b4906c276e76c3" + integrity sha512-/is78VKbKs70bVZH7w4YaZea6xcJWOAwkhbR0CFuZBmYtfTYF0xjGJF43AYd8g2Uii1yJwmS5GR2vBmrc32sbg== dependencies: - camelcase "^4.1.0" - -yargs@^10.0.3: - version "10.1.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" - integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig== - dependencies: - cliui "^4.0.0" - decamelize "^1.1.1" - find-up "^2.1.0" - get-caller-file "^1.0.1" - os-locale "^2.0.0" + cliui "^5.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" require-directory "^2.1.1" - require-main-filename "^1.0.1" + require-main-filename "^2.0.0" set-blocking "^2.0.0" - string-width "^2.0.0" + string-width "^3.0.0" which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^8.1.0" + y18n "^4.0.0" + yargs-parser "^15.0.0" yargs@^7.0.0: version "7.1.0" From 08bf0d8379284c9dc8725a6a40282e4000c1b99b Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 13 Nov 2019 15:42:33 +0530 Subject: [PATCH 021/153] feat: added orders API --- .../razorpay_settings/razorpay_settings.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py index 26e0de35b5..ca825a4ad7 100644 --- a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py +++ b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py @@ -180,6 +180,23 @@ class RazorpaySettings(Document): integration_request = create_request_log(kwargs, "Host", "Razorpay") return get_url("./integrations/razorpay_checkout?token={0}".format(integration_request.name)) + def create_order(self, **kwargs): + # Creating Orders https://razorpay.com/docs/api/orders/ + # + # kwargs = { + # "amount": 3000, + # "currency": "INR", + # "receipt": "rcptid_11234", + # "payment_capture": 1 + # } + integration_request = create_request_log(kwargs, "Host", "Razorpay") + if self.api_key and self.api_secret: + try: + return make_post_request("https://api.razorpay.com/v1/orders", auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False)), data=kwargs) + except Exception: + frappe.log(frappe.get_traceback()) + frappe.throw(_("Could not create razorpay order")) + def create_request(self, data): self.data = frappe._dict(data) From 46ef9411161726c76e6d4b5b39f9a98eb224a7ec Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 13 Nov 2019 17:37:02 +0530 Subject: [PATCH 022/153] fix: fixed post request --- .../doctype/razorpay_settings/razorpay_settings.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py index ca825a4ad7..16fe763722 100644 --- a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py +++ b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py @@ -190,9 +190,15 @@ class RazorpaySettings(Document): # "payment_capture": 1 # } integration_request = create_request_log(kwargs, "Host", "Razorpay") + payment_options = { + "amount": kwargs.get('amount'), + "currency": kwargs.get('currency', 'INR'), + "receipt": kwargs.get('receipt'), + "payment_capture": kwargs.get('payment_capture') + } if self.api_key and self.api_secret: try: - return make_post_request("https://api.razorpay.com/v1/orders", auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False)), data=kwargs) + return make_post_request("https://api.razorpay.com/v1/orders", auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False)), data=payment_options) except Exception: frappe.log(frappe.get_traceback()) frappe.throw(_("Could not create razorpay order")) From b8a4821a83d0f6da6a00f7f1af9bc60aa7a1acae Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 13 Nov 2019 19:31:11 +0530 Subject: [PATCH 023/153] feat: updated client API --- .../razorpay_settings/razorpay_settings.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py index 16fe763722..2a0f14f4b9 100644 --- a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py +++ b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py @@ -198,7 +198,9 @@ class RazorpaySettings(Document): } if self.api_key and self.api_secret: try: - return make_post_request("https://api.razorpay.com/v1/orders", auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False)), data=payment_options) + order = make_post_request("https://api.razorpay.com/v1/orders", auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False)), data=payment_options) + order['integration_request'] = integration_request + return order except Exception: frappe.log(frappe.get_traceback()) frappe.throw(_("Could not create razorpay order")) @@ -353,6 +355,22 @@ def capture_payment(is_sandbox=False, sanbox_response=None): doc.error = frappe.get_traceback() frappe.log_error(doc.error, '{0} Failed'.format(doc.name)) +@frappe.whitelist(allow_guest=True) +def get_order(doctype, docname): + return frappe.get_doc(doctype, docname).run_method("get_razorpay_order") + +@frappe.whitelist(allow_guest=True) +def order_payment_success(self, integration_request, params): + print("SUCCESSSSSSS ------------------") + integration = frappe.get_doc("Integration Request", integration_request) + integration.update_status(update_dict) + +@frappe.whitelist(allow_guest=True) +def order_payment_failure(self, integration_request, params): + print("FAILLLLLL ------------------") + integration = frappe.get_doc("Integration Request", integration_request) + integration.update_status(update_dict) + def convert_rupee_to_paisa(**kwargs): for addon in kwargs.get('addons'): addon['item']['amount'] *= 100 From afb8829514a41fcc86b5057be55f66a63268e194 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 13 Nov 2019 19:31:23 +0530 Subject: [PATCH 024/153] feat: created client API for razorpay --- frappe/public/build.json | 3 + frappe/public/js/integrations/razorpay.js | 170 +++++++++++++++++++--- 2 files changed, 150 insertions(+), 23 deletions(-) diff --git a/frappe/public/build.json b/frappe/public/build.json index 6c67c17374..e8cb32fa4d 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -13,6 +13,9 @@ "js/frappe-recorder.min.js": [ "public/js/frappe/recorder/recorder.js" ], + "js/checkout.min.js": [ + "public/js/integrations/razorpay.js" + ], "js/frappe-web.min.js": [ "public/js/frappe/class.js", "public/js/frappe/polyfill.js", diff --git a/frappe/public/js/integrations/razorpay.js b/frappe/public/js/integrations/razorpay.js index 0885826e5c..57dbdd8f61 100644 --- a/frappe/public/js/integrations/razorpay.js +++ b/frappe/public/js/integrations/razorpay.js @@ -1,26 +1,150 @@ -frappe.provide("frappe.integration_service") +// frappe.provide("frappe.integration_service") -frappe.integration_service.razorpay = { - load: function(frm) { - new frappe.integration_service.Razorpay(frm) - }, - scheduler_job_helper: function(){ - return { - "Every few minutes": "Check and capture new payments" +// frappe.integration_service.razorpay = { +// load: function(frm) { +// new frappe.integration_service.Razorpay(frm) +// }, +// scheduler_job_helper: function(){ +// return { +// "Every few minutes": "Check and capture new payments" +// } +// } +// } + +// frappe.integration_service.Razorpay = Class.extend({ +// init:function(frm){ +// this.frm = frm; +// this.frm.toggle_display("use_test_account", false); +// this.show_logs(); +// }, +// show_logs: function(){ +// this.frm.add_custom_button(__("Show Log"), function(frm){ +// frappe.route_options = {"integration_request_service": "Razorpay"}; +// frappe.set_route("List", "Integration Request"); +// }); +// } +// }) +// + +// function make_payment(order, ticket) { +// var options = { +// "key": "rzp_test_lExD7NVL1JoKJJ", // Enter the Key ID generated from the Dashboard +// "amount": order.amount_due, // Amount is in currency subunits. Default currency is INR. Hence, 50000 refers to 50000 paise or INR 500. +// "currency": order.currency, +// "name": "IndiaOS", +// "description": "Conference Ticket", +// "image": "http://indiaos.in/assets/indiaos/img/icons/favicon.ico", +// "order_id": order.id, +// "prefill": { +// "name": ticket.full_name, +// "email": ticket.email, +// "contact": '7506056962' +// }, +// "theme": { +// "color": "#F6E05E" +// } +// }; + +// options.handler = function (response){ +// if (response.error) { +// openModal(); +// fail('payment-failed'); +// } + +// if (response.razorpay_payment_id) { +// openModal(); +// success(); + +// } +// } + +// var razorpay = new Razorpay(options); +// razorpay.once('ready', function(response) { +// modalClose(); +// }) + +// razorpay.open(); + +frappe.provide("frappe.checkout") + +frappe.require('https://checkout.razorpay.com/v1/checkout.js').then(() => { + frappe.checkout.razorpay = class RazorpayCheckout { + constructor(opts) { + Object.assign(this, opts); + } + + init() { + frappe.run_serially([ + () => this.makeOrder(), + () => this.prepareOptions(), + () => this.setupHandler(), + () => this.show() + ]) + } + + show(callback=null) { + let razorpay = new Razorpay(this.options); + razorpay.once('ready', function(response) { + this.onOpen && this.onOpen(response); + }) + razorpay.open(); + } + + makeOrder() { + return new Promise(resolve => { + frappe.call( "frappe.integrations.doctype.razorpay_settings.razorpay_settings.get_order", { + doctype: this.doctype, + docname: this.docname + }).then(res => { + this.order = res.message + resolve(true); + }) + }); + } + + orderSuccess(response) { + frappe.call( "frappe.integrations.doctype.razorpay_settings.razorpay_settings.order_payment_success", { + integration_request: this.order.integration_request, + params: { + razorpay_payment_id: response.razorpay_payment_id, + razorpay_order_id: response.razorpay_order_id, + razorpay_signature: response.razorpay_signature + } + }) + } + + orderFail() { + frappe.call( "frappe.integrations.doctype.razorpay_settings.razorpay_settings.order_payment_failure", { + integration_request: this.order.integration_request, + params: response + }) + } + + prepareOptions() { + this.options = { + "key": this.key, + "amount": this.order.amount_due, + "currency": this.order.currency, + "name": this.name, + "description": this.description, + "image": this.image, + "order_id": this.order.id, + "prefill": this.prefill, + "theme": this.theme + }; + } + + setupHandler() { + this.options.handler = (response) => { + if (response.error) { + this.orderFail(response); + this.onFail && this.onFail(response); + } + if (response.razorpay_payment_id) { + this.orderSuccess(response); + this.onSuccess && this.onSuccess(response); + } + } } } -} - -frappe.integration_service.Razorpay = Class.extend({ - init:function(frm){ - this.frm = frm; - this.frm.toggle_display("use_test_account", false); - this.show_logs(); - }, - show_logs: function(){ - this.frm.add_custom_button(__("Show Log"), function(frm){ - frappe.route_options = {"integration_request_service": "Razorpay"}; - frappe.set_route("List", "Integration Request"); - }); - } -}) +}) \ No newline at end of file From e67b635673ef31f81189b411a6de74d13e869d6c Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 13 Nov 2019 19:35:55 +0530 Subject: [PATCH 025/153] style: removed commented code --- frappe/public/js/integrations/razorpay.js | 67 ----------------------- 1 file changed, 67 deletions(-) diff --git a/frappe/public/js/integrations/razorpay.js b/frappe/public/js/integrations/razorpay.js index 57dbdd8f61..3bc841d1be 100644 --- a/frappe/public/js/integrations/razorpay.js +++ b/frappe/public/js/integrations/razorpay.js @@ -1,70 +1,3 @@ -// frappe.provide("frappe.integration_service") - -// frappe.integration_service.razorpay = { -// load: function(frm) { -// new frappe.integration_service.Razorpay(frm) -// }, -// scheduler_job_helper: function(){ -// return { -// "Every few minutes": "Check and capture new payments" -// } -// } -// } - -// frappe.integration_service.Razorpay = Class.extend({ -// init:function(frm){ -// this.frm = frm; -// this.frm.toggle_display("use_test_account", false); -// this.show_logs(); -// }, -// show_logs: function(){ -// this.frm.add_custom_button(__("Show Log"), function(frm){ -// frappe.route_options = {"integration_request_service": "Razorpay"}; -// frappe.set_route("List", "Integration Request"); -// }); -// } -// }) -// - -// function make_payment(order, ticket) { -// var options = { -// "key": "rzp_test_lExD7NVL1JoKJJ", // Enter the Key ID generated from the Dashboard -// "amount": order.amount_due, // Amount is in currency subunits. Default currency is INR. Hence, 50000 refers to 50000 paise or INR 500. -// "currency": order.currency, -// "name": "IndiaOS", -// "description": "Conference Ticket", -// "image": "http://indiaos.in/assets/indiaos/img/icons/favicon.ico", -// "order_id": order.id, -// "prefill": { -// "name": ticket.full_name, -// "email": ticket.email, -// "contact": '7506056962' -// }, -// "theme": { -// "color": "#F6E05E" -// } -// }; - -// options.handler = function (response){ -// if (response.error) { -// openModal(); -// fail('payment-failed'); -// } - -// if (response.razorpay_payment_id) { -// openModal(); -// success(); - -// } -// } - -// var razorpay = new Razorpay(options); -// razorpay.once('ready', function(response) { -// modalClose(); -// }) - -// razorpay.open(); - frappe.provide("frappe.checkout") frappe.require('https://checkout.razorpay.com/v1/checkout.js').then(() => { From c7edd0ac466e1edb92b7a0b25bc7f9574063ae38 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2019 23:23:15 +0000 Subject: [PATCH 026/153] chore(deps): [security] bump markdown2 from 2.3.5 to 2.3.6 Bumps [markdown2](https://github.com/trentm/python-markdown2) from 2.3.5 to 2.3.6. **This update includes a security fix.** - [Release notes](https://github.com/trentm/python-markdown2/releases) - [Changelog](https://github.com/trentm/python-markdown2/blob/master/CHANGES.md) - [Commits](https://github.com/trentm/python-markdown2/compare/2.3.5...2.3.6) Signed-off-by: dependabot-preview[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 84788c863e..2db499d53f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ chardet dropbox==9.1.0 gunicorn jinja2 -markdown2==2.3.5 +markdown2==2.3.6 PyMySQL maxminddb-geolite2 python-dateutil From baa8f8be50a53470e481921a381c9b9dabb925bb Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 Nov 2019 11:44:04 +0530 Subject: [PATCH 027/153] style: added comments and cleaned up API --- .../razorpay_settings/razorpay_settings.py | 80 +++++++++++++------ frappe/public/js/integrations/razorpay.js | 55 +++++++++++++ 2 files changed, 111 insertions(+), 24 deletions(-) diff --git a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py index 2a0f14f4b9..03153f4049 100644 --- a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py +++ b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py @@ -182,14 +182,14 @@ class RazorpaySettings(Document): def create_order(self, **kwargs): # Creating Orders https://razorpay.com/docs/api/orders/ - # - # kwargs = { - # "amount": 3000, - # "currency": "INR", - # "receipt": "rcptid_11234", - # "payment_capture": 1 - # } + + # convert ruppes to paisa + kwargs['amount'] *= 100 + + # Create integration log integration_request = create_request_log(kwargs, "Host", "Razorpay") + + # Setup payment otptions payment_options = { "amount": kwargs.get('amount'), "currency": kwargs.get('currency', 'INR'), @@ -199,8 +199,8 @@ class RazorpaySettings(Document): if self.api_key and self.api_secret: try: order = make_post_request("https://api.razorpay.com/v1/orders", auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False)), data=payment_options) - order['integration_request'] = integration_request - return order + order['integration_request'] = integration_request.name + return order # Order returned to be consumed by razorpay.js except Exception: frappe.log(frappe.get_traceback()) frappe.throw(_("Could not create razorpay order")) @@ -238,6 +238,10 @@ class RazorpaySettings(Document): self.integration_request.update_status(data, 'Authorized') self.flags.status_changed_to = "Authorized" + if resp.get("status") == "captured": + self.integration_request.update_status(data, 'Completed') + self.flags.status_changed_to = "Completed" + elif data.get('subscription_id'): if resp.get("status") == "refunded": # if subscription start date is in future then @@ -247,14 +251,6 @@ class RazorpaySettings(Document): self.integration_request.update_status(data, 'Completed') self.flags.status_changed_to = "Verified" - if resp.get("status") == "captured": - # if subscription starts immediately then - # razorpay charge the actual amount - # thus changing status to Completed - - self.integration_request.update_status(data, 'Completed') - self.flags.status_changed_to = "Completed" - else: frappe.log_error(str(resp), 'Razorpay Payment not authorized') @@ -357,19 +353,55 @@ def capture_payment(is_sandbox=False, sanbox_response=None): @frappe.whitelist(allow_guest=True) def get_order(doctype, docname): - return frappe.get_doc(doctype, docname).run_method("get_razorpay_order") + # Order returned to be consumed by razorpay.js + doc = frappe.get_doc(doctype, docname) + try: + # Do not use run_method here as it fails silently + return doc.get_razorpay_order() + except AttributeError: + error_log = frappe.log_error(frappe.get_traceback(), _("Controller method get_razorpay_order missing")) + frappe.throw(_("Could not create Razorpay order. Please contact Administrator")) @frappe.whitelist(allow_guest=True) -def order_payment_success(self, integration_request, params): - print("SUCCESSSSSSS ------------------") +def order_payment_success(integration_request, params): + """Called by razorpay.js on order payment success, the params + contains razorpay_payment_id, razorpay_order_id, razorpay_signature + that is updated in the data field of integration request + + Args: + integration_request (string): Name for integration request doc + params (string): Params to be updated for integration request. + """ + params = json.loads(params) integration = frappe.get_doc("Integration Request", integration_request) - integration.update_status(update_dict) + + # Update integration request + integration.update_status(params, integration.status) + integration.reload() + + data = json.loads(integration.data) + controller = frappe.get_doc("Razorpay Settings") + + # Update payment and integration data for payment controller object + controller.integration_request = integration + controller.data = frappe._dict(data) + + # Authorize payment + controller.authorize_payment() @frappe.whitelist(allow_guest=True) -def order_payment_failure(self, integration_request, params): - print("FAILLLLLL ------------------") +def order_payment_failure(integration_request, params): + """Called by razorpay.js on failure + + Args: + integration_request (TYPE): Description + params (TYPE): error data to be updated + """ + frappe.log_error(params, 'Razorpay Payment Failure') + + params = json.loads(params) integration = frappe.get_doc("Integration Request", integration_request) - integration.update_status(update_dict) + integration.update_status(params, integration.status) def convert_rupee_to_paisa(**kwargs): for addon in kwargs.get('addons'): diff --git a/frappe/public/js/integrations/razorpay.js b/frappe/public/js/integrations/razorpay.js index 3bc841d1be..c21fd28b0e 100644 --- a/frappe/public/js/integrations/razorpay.js +++ b/frappe/public/js/integrations/razorpay.js @@ -1,3 +1,58 @@ +/* HOW-TO + +Razorpay Payment + +1. Include checkout script in your code + + +2. Create the Order controller in your backend + def get_razorpay_order(self): + controller = get_payment_gateway_controller("Razorpay") + + payment_details = { + "amount": 300, + ... + "reference_doctype": "Conference Participant", + "reference_docname": self.name, + ... + "receipt": self.name + } + + return controller.create_order(**payment_details) + +3. Inititate the payment in client using checkout API + function make_payment(ticket) { + var options = { + "key": "", + "name": "", + "description": "", + "image": "", + "prefill": { + "name": "", + "email": "", + "contact": "" + }, + "theme": { + "color": "" + }, + "doctype": "", + "docname": " { + -2. Create the Order controller in your backend +2. Create the Order controller in your backend def get_razorpay_order(self): controller = get_payment_gateway_controller("Razorpay") - + payment_details = { "amount": 300, ... @@ -39,13 +39,13 @@ Razorpay Payment }; razorpay = new frappe.checkout.razorpay(options) - razorpay.onOpen = () => { + razorpay.on_open = () => {