Merge branch 'develop' into ci/reports
This commit is contained in:
commit
5d12770de8
55 changed files with 735 additions and 662 deletions
55
cypress/integration/control_barcode.js
Normal file
55
cypress/integration/control_barcode.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
context('Control Barcode', () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
cy.visit('/desk');
|
||||
});
|
||||
|
||||
function get_dialog_with_barcode() {
|
||||
return cy.dialog({
|
||||
title: 'Barcode',
|
||||
fields: [
|
||||
{
|
||||
label: 'Barcode',
|
||||
fieldname: 'barcode',
|
||||
fieldtype: 'Barcode'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
it('should generate barcode on setting a value', () => {
|
||||
get_dialog_with_barcode().as('dialog');
|
||||
|
||||
cy.get('.frappe-control[data-fieldname=barcode] input')
|
||||
.focus()
|
||||
.type('123456789')
|
||||
.blur();
|
||||
cy.get('.frappe-control[data-fieldname=barcode] svg[data-barcode-value="123456789"]')
|
||||
.should('exist');
|
||||
|
||||
cy.get('@dialog').then(dialog => {
|
||||
let value = dialog.get_value('barcode');
|
||||
expect(value).to.contain('<svg');
|
||||
expect(value).to.contain('data-barcode-value="123456789"');
|
||||
});
|
||||
});
|
||||
|
||||
it('should reset when input is cleared', () => {
|
||||
get_dialog_with_barcode().as('dialog');
|
||||
|
||||
cy.get('.frappe-control[data-fieldname=barcode] input')
|
||||
.focus()
|
||||
.type('123456789')
|
||||
.blur();
|
||||
cy.get('.frappe-control[data-fieldname=barcode] input')
|
||||
.clear()
|
||||
.blur();
|
||||
cy.get('.frappe-control[data-fieldname=barcode] svg[data-barcode-value="123456789"]')
|
||||
.should('not.exist');
|
||||
|
||||
cy.get('@dialog').then(dialog => {
|
||||
let value = dialog.get_value('barcode');
|
||||
expect(value).to.equal('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -61,12 +61,18 @@ context('Control Link', () => {
|
|||
|
||||
cy.server();
|
||||
cy.route('GET', '/api/method/frappe.desk.form.utils.validate_link*').as('validate_link');
|
||||
cy.route('POST', '/api/method/frappe.desk.search.search_link').as('search_link');
|
||||
|
||||
cy.get('@todos').then(todos => {
|
||||
cy.get('.frappe-control[data-fieldname=link] input').type(todos[0]).blur();
|
||||
cy.get('.frappe-control[data-fieldname=link] input').as('input');
|
||||
cy.get('@input').focus();
|
||||
cy.wait('@search_link');
|
||||
cy.get('@input').type(todos[0]).blur();
|
||||
cy.wait('@validate_link');
|
||||
cy.get('.frappe-control[data-fieldname=link] input').focus();
|
||||
cy.get('.frappe-control[data-fieldname=link] .link-btn').click();
|
||||
cy.get('@input').focus();
|
||||
cy.get('.frappe-control[data-fieldname=link] .link-btn')
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.location('hash').should('eq', `#Form/ToDo/${todos[0]}`);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ def log(msg):
|
|||
|
||||
debug_log.append(as_unicode(msg))
|
||||
|
||||
def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None, alert=False):
|
||||
def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None, alert=False, primary_action=None):
|
||||
"""Print a message to the user (via HTTP response).
|
||||
Messages are sent in the `__server_messages` property in the
|
||||
response JSON and shown in a pop-up / modal.
|
||||
|
|
@ -299,6 +299,7 @@ def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None,
|
|||
:param title: [optional] Message title.
|
||||
: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.
|
||||
:param primary_action: [optional] Bind a primary server/client side action.
|
||||
"""
|
||||
from frappe.utils import encode
|
||||
|
||||
|
|
@ -338,6 +339,9 @@ def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None,
|
|||
if alert:
|
||||
out.alert = 1
|
||||
|
||||
if primary_action:
|
||||
out.primary_action = primary_action
|
||||
|
||||
message_log.append(json.dumps(out))
|
||||
|
||||
if raise_exception and hasattr(raise_exception, '__name__'):
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@
|
|||
"fieldtype": "Link",
|
||||
"label": "User",
|
||||
"options": "User",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "Online",
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@
|
|||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Token",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "ip_address",
|
||||
|
|
|
|||
|
|
@ -145,30 +145,10 @@ def get_list_context(context=None):
|
|||
def get_address_list(doctype, txt, filters, limit_start, limit_page_length = 20, order_by = None):
|
||||
from frappe.www.list import get_list
|
||||
user = frappe.session.user
|
||||
ignore_permissions = False
|
||||
if is_website_user():
|
||||
if not filters: filters = []
|
||||
add_name = []
|
||||
contact = frappe.db.sql("""
|
||||
select
|
||||
address.name
|
||||
from
|
||||
`tabDynamic Link` as link
|
||||
join
|
||||
`tabAddress` as address on link.parent = address.name
|
||||
where
|
||||
link.parenttype = 'Address' and
|
||||
link_name in(
|
||||
select
|
||||
link.link_name from `tabContact` as contact
|
||||
join
|
||||
`tabDynamic Link` as link on contact.name = link.parent
|
||||
where
|
||||
contact.user = %s)""",(user))
|
||||
for c in contact:
|
||||
add_name.append(c[0])
|
||||
filters.append(("Address", "name", "in", add_name))
|
||||
ignore_permissions = True
|
||||
ignore_permissions = True
|
||||
|
||||
if not filters: filters = []
|
||||
filters.append(("Address", "owner", "=", user))
|
||||
|
||||
return get_list(doctype, txt, filters, limit_start, limit_page_length, ignore_permissions=ignore_permissions)
|
||||
|
||||
|
|
|
|||
|
|
@ -81,9 +81,9 @@ def get_feed_match_conditions(user=None, doctype='Comment'):
|
|||
|
||||
if user_permissions:
|
||||
can_read_docs = []
|
||||
for doctype, obj in user_permissions.items():
|
||||
for dt, obj in user_permissions.items():
|
||||
for n in obj:
|
||||
can_read_docs.append('{}|{}'.format(doctype, frappe.db.escape(n.get('doc', ''))))
|
||||
can_read_docs.append('{}|{}'.format(frappe.db.escape(dt), frappe.db.escape(n.get('doc', ''))))
|
||||
|
||||
if can_read_docs:
|
||||
conditions.append("concat_ws('|', `tab{doctype}`.reference_doctype, `tab{doctype}`.reference_name) in ({values})".format(
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ frappe.ui.form.on("Communication", {
|
|||
frm.convert_to_click && frm.set_convert_button();
|
||||
frm.subject_field = "subject";
|
||||
|
||||
// content field contains weird table html that does not render well in Quill
|
||||
// this field is not to be edited directly anyway, so setting it as read only
|
||||
frm.set_df_property('content', 'read_only', 1);
|
||||
|
||||
if(frm.doc.reference_doctype && frm.doc.reference_name) {
|
||||
frm.add_custom_button(__(frm.doc.reference_name), function() {
|
||||
frappe.set_route("Form", frm.doc.reference_doctype, frm.doc.reference_name);
|
||||
|
|
|
|||
|
|
@ -3,19 +3,20 @@
|
|||
|
||||
frappe.ui.form.on('Data Import', {
|
||||
onload: function(frm) {
|
||||
if(frm.doc.__islocal) {
|
||||
if (frm.doc.__islocal) {
|
||||
frm.set_value("action", "");
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
method: "frappe.core.doctype.data_import.data_import.get_importable_doc",
|
||||
method: "frappe.core.doctype.data_import.data_import.get_importable_doctypes",
|
||||
callback: function (r) {
|
||||
let importable_doctypes = r.message;
|
||||
frm.set_query("reference_doctype", function () {
|
||||
return {
|
||||
"filters": {
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"name": ['in', r.message]
|
||||
"name": ['in', importable_doctypes]
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,9 +30,8 @@ class DataImport(Document):
|
|||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_importable_doc():
|
||||
import_lst = frappe.cache().hget("can_import", frappe.session.user)
|
||||
return import_lst
|
||||
def get_importable_doctypes():
|
||||
return frappe.cache().hget("can_import", frappe.session.user)
|
||||
|
||||
@frappe.whitelist()
|
||||
def import_data(data_import):
|
||||
|
|
|
|||
|
|
@ -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 != 'Report Builder':
|
||||
frappe.only_for('Script Manager', True)
|
||||
|
||||
if frappe.db.get_value("Report", self.name, "is_standard") == "Yes":
|
||||
|
|
|
|||
|
|
@ -56,8 +56,10 @@ def get_server_script_map():
|
|||
script_map = frappe.cache().get_value('server_script_map')
|
||||
if script_map is None:
|
||||
script_map = {}
|
||||
for script in frappe.get_all('Server Script', ('name', 'reference_doctype', 'doctype_event',
|
||||
'api_method', 'script_type')):
|
||||
enabled_server_scripts = frappe.get_all('Server Script',
|
||||
fields=('name', 'reference_doctype', 'doctype_event','api_method', 'script_type'),
|
||||
filters={'disabled': 0})
|
||||
for script in enabled_server_scripts:
|
||||
if script.script_type == 'DocType Event':
|
||||
script_map.setdefault(script.reference_doctype, {}).setdefault(script.doctype_event, []).append(script.name)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from frappe.utils import cint, has_gravatar, format_datetime, now_datetime, get_
|
|||
from frappe import throw, msgprint, _
|
||||
from frappe.utils.password import update_password as _update_password
|
||||
from frappe.desk.notifications import clear_notifications
|
||||
from frappe.desk.doctype.notification_settings.notification_settings import create_notification_settings
|
||||
from frappe.utils.user import get_system_managers
|
||||
from bs4 import BeautifulSoup
|
||||
import frappe.permissions
|
||||
|
|
@ -46,6 +47,9 @@ class User(Document):
|
|||
self.flags.in_insert = True
|
||||
throttle_user_creation()
|
||||
|
||||
def after_insert(self):
|
||||
create_notification_settings(self.name)
|
||||
|
||||
def validate(self):
|
||||
self.check_demo()
|
||||
|
||||
|
|
@ -364,6 +368,9 @@ class User(Document):
|
|||
if frappe.db.exists("Chat Profile", old_name):
|
||||
frappe.rename_doc("Chat Profile", old_name, new_name, force=True)
|
||||
|
||||
if frappe.db.exists("Notification Settings", old_name):
|
||||
frappe.rename_doc("Notification Settings", old_name, new_name, force=True)
|
||||
|
||||
# set email
|
||||
frappe.db.sql("""UPDATE `tabUser`
|
||||
SET email = %s
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
.version-info {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.version-info pre {
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
|
|
@ -14,4 +18,4 @@
|
|||
|
||||
.version-info .danger {
|
||||
background-color: #f2dede !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"email_content",
|
||||
"column_break_4",
|
||||
"document_type",
|
||||
"seen",
|
||||
"read",
|
||||
"document_name",
|
||||
"from_user"
|
||||
],
|
||||
|
|
@ -57,14 +57,6 @@
|
|||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "seen",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Seen"
|
||||
},
|
||||
{
|
||||
"fieldname": "document_name",
|
||||
"fieldtype": "Data",
|
||||
|
|
@ -79,11 +71,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-12 15:22:35.283678",
|
||||
"modified_by": "umair@erpnext.com",
|
||||
"module": "Desk",
|
||||
"name": "Notification Log",
|
||||
"owner": "Administrator",
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@ import frappe
|
|||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.desk.doctype.notification_settings.notification_settings import (is_notifications_enabled,
|
||||
is_email_notifications_enabled, is_email_notifications_enabled_for_type)
|
||||
is_email_notifications_enabled, is_email_notifications_enabled_for_type, set_seen_value)
|
||||
|
||||
class NotificationLog(Document):
|
||||
def after_insert(self):
|
||||
frappe.publish_realtime('notification', after_commit=True, user=self.for_user)
|
||||
set_notifications_as_unseen(self.for_user)
|
||||
if is_email_notifications_enabled(self.for_user):
|
||||
send_notification_email(self)
|
||||
|
||||
|
|
@ -64,13 +65,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('<div>', '').replace('</div>', '')
|
||||
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('<div>', '').replace('</div>', '')
|
||||
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)
|
||||
|
|
@ -112,11 +113,25 @@ def get_email_header(doc):
|
|||
|
||||
|
||||
@frappe.whitelist()
|
||||
def mark_as_seen(docname):
|
||||
if docname:
|
||||
frappe.db.set_value('Notification Log', docname, 'seen', 1, update_modified=False)
|
||||
def mark_all_as_read():
|
||||
unread_docs_list = frappe.db.get_all('Notification Log', filters = {'read': 0, 'for_user': frappe.session.user})
|
||||
unread_docnames = [doc.name for doc in unread_docs_list]
|
||||
if unread_docnames:
|
||||
filters = {'name': ['in', unread_docnames]}
|
||||
frappe.db.set_value('Notification Log', filters, 'read', 1, update_modified=False)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def mark_as_read(docname):
|
||||
if docname:
|
||||
frappe.db.set_value('Notification Log', docname, 'read', 1, update_modified=False)
|
||||
|
||||
@frappe.whitelist()
|
||||
def trigger_indicator_hide():
|
||||
frappe.publish_realtime('indicator_hide', user=frappe.session.user)
|
||||
|
||||
def set_notifications_as_unseen(user):
|
||||
try:
|
||||
frappe.db.set_value('Notification Settings', user, 'seen', 0)
|
||||
except frappe.DoesNotExistError:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@
|
|||
"enable_email_assignment",
|
||||
"enable_email_energy_point",
|
||||
"enable_email_share",
|
||||
"user"
|
||||
"user",
|
||||
"seen"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
|
|
@ -72,14 +73,20 @@
|
|||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "User",
|
||||
"options": "User",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "seen",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Seen"
|
||||
}
|
||||
],
|
||||
"in_create": 1,
|
||||
"modified": "2019-10-23 12:42:56.175928",
|
||||
"modified": "2019-11-19 12:57:59.356786",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Desk",
|
||||
"name": "Notification Settings",
|
||||
|
|
|
|||
|
|
@ -31,12 +31,12 @@ def is_email_notifications_enabled_for_type(user, notification_type):
|
|||
return True
|
||||
return enabled
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_notification_settings():
|
||||
_doc = frappe.new_doc('Notification Settings')
|
||||
_doc.name = frappe.session.user
|
||||
_doc.insert(ignore_permissions=True)
|
||||
frappe.db.commit()
|
||||
def create_notification_settings(user):
|
||||
if not frappe.db.exists("Notification Settings", user):
|
||||
_doc = frappe.new_doc('Notification Settings')
|
||||
_doc.name = user
|
||||
_doc.insert(ignore_permissions=True)
|
||||
frappe.db.commit()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
|
|
@ -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, user):
|
||||
frappe.db.set_value('Notification Settings', user, 'seen', value, update_modified=False)
|
||||
|
|
@ -184,7 +184,7 @@ frappe.ui.form.on("Email Account", {
|
|||
read as well as unread message from server. This may also cause the duplication\
|
||||
of Communication (emails).");
|
||||
frappe.confirm(msg, null, function() {
|
||||
frm.set_value("email_sync_option", "UNSEEN");
|
||||
frm.set_value("email_sync_option", "ALL");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -180,6 +180,33 @@ 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/
|
||||
|
||||
# convert rupees to paisa
|
||||
kwargs['amount'] *= 100
|
||||
|
||||
# Create integration log
|
||||
integration_request = create_request_log(kwargs, "Host", "Razorpay")
|
||||
|
||||
# Setup payment options
|
||||
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:
|
||||
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.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"))
|
||||
|
||||
def create_request(self, data):
|
||||
self.data = frappe._dict(data)
|
||||
|
||||
|
|
@ -213,6 +240,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
|
||||
|
|
@ -222,14 +253,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')
|
||||
|
||||
|
|
@ -242,7 +265,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
|
||||
|
|
@ -330,6 +352,63 @@ 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_api_key():
|
||||
controller = frappe.get_doc("Razorpay Settings")
|
||||
return controller.api_key
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def get_order(doctype, docname):
|
||||
# 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:
|
||||
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(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)
|
||||
|
||||
# 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(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(params, integration.status)
|
||||
|
||||
def convert_rupee_to_paisa(**kwargs):
|
||||
for addon in kwargs.get('addons'):
|
||||
addon['item']['amount'] *= 100
|
||||
|
|
@ -383,4 +462,4 @@ def validate_payment_callback(data):
|
|||
_throw()
|
||||
|
||||
def handle_subscription_notification(doctype, docname):
|
||||
call_hook_method("handle_subscription_notification", doctype=doctype, docname=docname)
|
||||
call_hook_method("handle_subscription_notification", doctype=doctype, docname=docname)
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ frappe.patches.v12_0.move_email_and_phone_to_child_table
|
|||
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
|
||||
frappe.patches.v12_0.update_auto_repeat_status_and_not_submittable
|
||||
frappe.patches.v12_0.copy_to_parent_for_tags
|
||||
frappe.patches.v12_0.create_notification_settings_for_user
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.desk.doctype.notification_settings.notification_settings import create_notification_settings
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('desk', 'doctype', 'notification_settings')
|
||||
frappe.reload_doc('desk', 'doctype', 'notification_subscribed_document')
|
||||
|
||||
users = frappe.db.get_all('User', fields=['name'])
|
||||
for user in users:
|
||||
create_notification_settings(user.name)
|
||||
|
|
@ -18,6 +18,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",
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -367,6 +367,13 @@ export default {
|
|||
if (this.on_success) {
|
||||
this.on_success(file_doc, r);
|
||||
}
|
||||
} else if (xhr.status === 403) {
|
||||
let response = JSON.parse(xhr.responseText);
|
||||
frappe.msgprint({
|
||||
title: __('Not permitted'),
|
||||
indicator: 'red',
|
||||
message: response._error_message
|
||||
});
|
||||
} else {
|
||||
file.failed = true;
|
||||
let error = null;
|
||||
|
|
|
|||
|
|
@ -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 = '<svg height=80></svg>';
|
||||
let $input_wrapper = this.$wrapper.find('.control-input-wrapper');
|
||||
this.barcode_area = $(`<div class="barcode-wrapper border"><svg height=80></svg></div>`);
|
||||
this.barcode_area = $(
|
||||
`<div class="barcode-wrapper border">${this.default_svg}</div>`
|
||||
);
|
||||
this.barcode_area.appendTo($input_wrapper);
|
||||
},
|
||||
|
||||
parse(value) {
|
||||
// Parse raw value
|
||||
return value ? this.get_barcode_html(value) : "";
|
||||
if (value) {
|
||||
if (value.startsWith('<svg')) {
|
||||
return value;
|
||||
}
|
||||
return this.get_barcode_html(value);
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
set_formatted_input(value) {
|
||||
|
|
@ -20,47 +29,39 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
|
|||
let svg = value;
|
||||
const barcode_value = $(svg).attr('data-barcode-value');
|
||||
|
||||
if(!barcode_value) {
|
||||
if (!barcode_value && this.doc) {
|
||||
svg = this.get_barcode_html(value);
|
||||
this.doc[this.df.fieldname] = svg;
|
||||
}
|
||||
|
||||
this.$input.val(barcode_value || value);
|
||||
this.barcode_area.html(svg);
|
||||
this.barcode_area.html(svg || this.default_svg);
|
||||
},
|
||||
|
||||
get_barcode_html(value) {
|
||||
// Get svg
|
||||
const svg = this.barcode_area.find('svg')[0];
|
||||
JsBarcode(svg, value, this.get_options(value));
|
||||
$(svg).attr('data-barcode-value', value);
|
||||
return this.barcode_area.html();
|
||||
if (value) {
|
||||
// Get svg
|
||||
const svg = this.barcode_area.find('svg')[0];
|
||||
JsBarcode(svg, value, this.get_options(value));
|
||||
$(svg).attr('data-barcode-value', value);
|
||||
return this.barcode_area.html();
|
||||
}
|
||||
},
|
||||
|
||||
get_options(value) {
|
||||
// get JsBarcode options
|
||||
let options = JSON.parse('{ "height" : 40 }');
|
||||
if (this.isValidJson(this.df.options)) {
|
||||
if (frappe.utils.is_json(this.df.options)) {
|
||||
options = JSON.parse(this.df.options);
|
||||
if (options.format && options.format === "EAN") {
|
||||
options.format = value.length == 8 ? "EAN8" : "EAN13";
|
||||
if (options.format && options.format === 'EAN') {
|
||||
options.format = value.length == 8 ? 'EAN8' : 'EAN13';
|
||||
}
|
||||
|
||||
if (options.valueField) {
|
||||
// Set companion field value
|
||||
this.frm.set_value(options.valueField, value);
|
||||
this.frm && this.frm.set_value(options.valueField, value);
|
||||
}
|
||||
}
|
||||
return options;
|
||||
},
|
||||
|
||||
isValidJson(jsonData) {
|
||||
try {
|
||||
JSON.parse(jsonData);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ frappe.ui.form.ControlCheck = frappe.ui.form.ControlData.extend({
|
|||
return cint(value);
|
||||
},
|
||||
set_input: function(value) {
|
||||
value = cint(value);
|
||||
if(this.input) {
|
||||
this.input.checked = (value ? 1 : 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,9 @@ frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
|
|||
});
|
||||
|
||||
this.$list_wrapper.on('keydown', e => {
|
||||
if ($(e.target).is('input')) {
|
||||
return;
|
||||
}
|
||||
if (e.key === 'Backspace') {
|
||||
this.set_value([]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export default class Grid {
|
|||
|
||||
let template = `<div class="form-group">
|
||||
<div class="clearfix">
|
||||
<label class="control-label" style="padding-right: 0px;">${__(this.df.label)}</label>
|
||||
<label class="control-label" style="padding-right: 0px;">${__(this.df.label || '')}</label>
|
||||
</div>
|
||||
<div class="form-grid">
|
||||
<div class="grid-heading-row"></div>
|
||||
|
|
|
|||
|
|
@ -614,7 +614,7 @@ class FilterArea {
|
|||
let options = df.options;
|
||||
let condition = '=';
|
||||
let fieldtype = df.fieldtype;
|
||||
if (['Text', 'Small Text', 'Text Editor', 'Data'].includes(fieldtype)) {
|
||||
if (['Text', 'Small Text', 'Text Editor', 'Data', 'Code'].includes(fieldtype)) {
|
||||
fieldtype = 'Data';
|
||||
condition = 'like';
|
||||
}
|
||||
|
|
@ -625,17 +625,13 @@ class FilterArea {
|
|||
options = options.join("\n");
|
||||
}
|
||||
}
|
||||
let default_value = (fieldtype === 'Link') ? frappe.defaults.get_user_default(options) : null;
|
||||
if (['__default', '__global'].includes(default_value)) {
|
||||
default_value = null;
|
||||
}
|
||||
|
||||
return {
|
||||
fieldtype: fieldtype,
|
||||
label: __(df.label),
|
||||
options: options,
|
||||
fieldname: df.fieldname,
|
||||
condition: condition,
|
||||
default: default_value,
|
||||
onchange: () => this.refresh_list_view(),
|
||||
ignore_link_validation: fieldtype === 'Dynamic Link'
|
||||
};
|
||||
|
|
@ -650,6 +646,13 @@ class FilterArea {
|
|||
for (let key in fields_dict) {
|
||||
let field = fields_dict[key];
|
||||
let value = field.get_value();
|
||||
let default_value = (field.df.fieldtype === 'Link') ?
|
||||
frappe.defaults.get_user_default(field.df.options) : null;
|
||||
|
||||
if (['__default', '__global'].includes(default_value)) {
|
||||
default_value = null;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
if (field.df.condition === 'like' && !value.includes('%')) {
|
||||
value = '%' + value + '%';
|
||||
|
|
@ -660,6 +663,13 @@ class FilterArea {
|
|||
field.df.condition || '=',
|
||||
value
|
||||
]);
|
||||
} else if (default_value) {
|
||||
filters.push([
|
||||
this.list_view.doctype,
|
||||
field.df.fieldname,
|
||||
field.df.condition,
|
||||
default_value
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1077,10 +1077,21 @@ 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}']`).prop('checked', true);
|
||||
});
|
||||
this.on_row_checked();
|
||||
}
|
||||
|
||||
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');
|
||||
|
|
|
|||
|
|
@ -525,7 +525,13 @@ $.extend(frappe.model, {
|
|||
},
|
||||
|
||||
delete_doc: function(doctype, docname, callback) {
|
||||
frappe.confirm(__("Permanently delete {0}?", [docname]), function() {
|
||||
var title = docname;
|
||||
var title_field = frappe.get_meta(doctype).title_field;
|
||||
if (frappe.get_meta(doctype).autoname == "hash" && title_field) {
|
||||
var title = frappe.model.get_value(doctype, docname, title_field);
|
||||
title += " (" + docname + ")";
|
||||
}
|
||||
frappe.confirm(__("Permanently delete {0}?", [title]), function() {
|
||||
return frappe.call({
|
||||
method: 'frappe.client.delete',
|
||||
args: {
|
||||
|
|
|
|||
|
|
@ -120,12 +120,6 @@ frappe.msgprint = function(msg, title) {
|
|||
}
|
||||
});
|
||||
|
||||
// setup and bind an action to the primary button
|
||||
if (data.primary_action) {
|
||||
frappe.msg_dialog.set_primary_action(__(data.primary_action.label || "Done"),
|
||||
data.primary_action.action);
|
||||
}
|
||||
|
||||
// class "msgprint" is used in tests
|
||||
frappe.msg_dialog.msg_area = $('<div class="msgprint">')
|
||||
.appendTo(frappe.msg_dialog.body);
|
||||
|
|
@ -137,6 +131,43 @@ frappe.msgprint = function(msg, title) {
|
|||
frappe.msg_dialog.indicator = frappe.msg_dialog.header.find('.indicator');
|
||||
}
|
||||
|
||||
// setup and bind an action to the primary button
|
||||
if (data.primary_action) {
|
||||
if (data.primary_action.server_action && typeof data.primary_action.server_action === 'string') {
|
||||
data.primary_action.action = () => {
|
||||
frappe.call({
|
||||
method: data.primary_action.server_action,
|
||||
args: {
|
||||
args: data.primary_action.args
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (data.primary_action.client_action && typeof data.primary_action.client_action === 'string') {
|
||||
let parts = data.primary_action.client_action.split('.');
|
||||
let obj = window;
|
||||
for (let part of parts) {
|
||||
obj = obj[part];
|
||||
}
|
||||
data.primary_action.action = () => {
|
||||
if (typeof obj === 'function') {
|
||||
obj(data.primary_action.args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frappe.msg_dialog.set_primary_action(
|
||||
__(data.primary_action.label || "Done"),
|
||||
data.primary_action.action
|
||||
);
|
||||
} else {
|
||||
if (frappe.msg_dialog.has_primary_action) {
|
||||
frappe.msg_dialog.get_primary_btn().addClass('hide');
|
||||
frappe.msg_dialog.has_primary_action = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(data.message==null) {
|
||||
data.message = '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
frappe.provide('frappe.search');
|
||||
|
||||
frappe.ui.Notifications = class Notifications {
|
||||
constructor() {
|
||||
frappe.model
|
||||
|
|
@ -29,16 +31,25 @@ 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.setup_notifications();
|
||||
this.bind_events();
|
||||
}
|
||||
|
||||
route_to_settings() {
|
||||
frappe.set_route(`#Form/Notification Settings/${frappe.session.user}`);
|
||||
}
|
||||
|
||||
setup_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();
|
||||
}
|
||||
});
|
||||
|
|
@ -204,7 +215,7 @@ frappe.ui.Notifications = class Notifications {
|
|||
change_activity_status() {
|
||||
if (this.$dropdown_list.find('.activity-status')) {
|
||||
this.$dropdown_list.find('.activity-status').replaceWith(
|
||||
`<a class="recent-item text-center text-muted"
|
||||
`<a class="recent-item text-center text-muted"
|
||||
href="#List/Notification Log">
|
||||
<div class="full-log-btn">${__('View Full Log')}</div>
|
||||
</a>`
|
||||
|
|
@ -212,26 +223,44 @@ 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');
|
||||
frappe.call(
|
||||
'frappe.desk.doctype.notification_log.notification_log.mark_all_as_read',
|
||||
);
|
||||
}
|
||||
|
||||
toggle_seen(flag) {
|
||||
frappe.call(
|
||||
'frappe.desk.doctype.notification_settings.notification_settings.set_seen_value',
|
||||
{
|
||||
value: cint(flag),
|
||||
user: frappe.session.user
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
get_notifications_list(limit) {
|
||||
|
|
@ -279,8 +308,8 @@ frappe.ui.Notifications = class Notifications {
|
|||
field.document_type,
|
||||
field.document_name
|
||||
);
|
||||
let seen_class = field.seen ? '' : 'unseen';
|
||||
let mark_seen_action = field.seen ? '': 'data-action="mark_as_seen"';
|
||||
let read_class = field.read ? '' : 'unread';
|
||||
let mark_read_action = field.read ? '': 'data-action="mark_as_read"';
|
||||
let message = field.subject;
|
||||
let title = message.match(/<b class="subject-title">(.*?)<\/b>/);
|
||||
message = title ? message.replace(title[1], frappe.ellipsis(title[1], 100)): message;
|
||||
|
|
@ -288,18 +317,18 @@ frappe.ui.Notifications = class Notifications {
|
|||
let user = field.from_user;
|
||||
let user_avatar = frappe.avatar(user, 'avatar-small user-avatar');
|
||||
let timestamp = frappe.datetime.comment_when(field.creation, true);
|
||||
let item_html =
|
||||
`<a class="recent-item ${seen_class}"
|
||||
let item_html =
|
||||
`<a class="recent-item ${read_class}"
|
||||
href="${doc_link}"
|
||||
data-name="${field.name}"
|
||||
${mark_seen_action}
|
||||
${mark_read_action}
|
||||
>
|
||||
${user_avatar}
|
||||
${message_html}
|
||||
<div class="notification-timestamp text-muted">
|
||||
${timestamp}
|
||||
</div>
|
||||
<span class="mark-read text-muted hidden-xs" data-action="explicitly_mark_as_seen">
|
||||
<span class="mark-read text-muted hidden-xs" data-action="explicitly_mark_as_read">
|
||||
${__('Mark as Read')}
|
||||
</span>
|
||||
</a>`;
|
||||
|
|
@ -329,18 +358,25 @@ frappe.ui.Notifications = class Notifications {
|
|||
let category_id = frappe.dom.get_unique_id();
|
||||
let settings_html =
|
||||
category.value === 'Notifications'
|
||||
? `<span class="notification-settings pull-right" data-action="make_and_route_to_settings">
|
||||
? `<span class="notification-settings pull-right" data-action="go_to_settings">
|
||||
${__('Settings')}
|
||||
</span>`
|
||||
: '';
|
||||
let mark_all_read_html =
|
||||
category.value === 'Notifications'
|
||||
? `<span class="mark-all-read pull-right" data-action="mark_all_as_read">
|
||||
${__('Mark all as Read')}
|
||||
</span>`
|
||||
: '';
|
||||
let html = `<li class="notifications-category">
|
||||
<li class="text-muted header"
|
||||
data-action="${category.action}"
|
||||
href="#${category_id}"
|
||||
href="#${category_id}"
|
||||
data-toggle="collapse">
|
||||
${category.label}
|
||||
<span class="octicon octicon-chevron-down collapse-indicator"></span>
|
||||
${settings_html}
|
||||
${mark_all_read_html}
|
||||
</li>
|
||||
<div id="${category_id}" class="collapse category-list" data-category="${category.value}">
|
||||
<div class="text-center text-muted notifications-loading">
|
||||
|
|
@ -364,20 +400,11 @@ frappe.ui.Notifications = class Notifications {
|
|||
);
|
||||
}
|
||||
|
||||
make_and_route_to_settings(e) {
|
||||
go_to_settings(e) {
|
||||
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();
|
||||
}
|
||||
|
||||
bind_events() {
|
||||
|
|
@ -418,22 +445,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.toggle_seen(true);
|
||||
if (this.$notification_indicator.is(':visible')) {
|
||||
this.$notification_indicator.hide();
|
||||
frappe.call(
|
||||
'frappe.desk.doctype.notification_log.notification_log.trigger_indicator_hide'
|
||||
);
|
||||
|
|
@ -490,4 +509,4 @@ frappe.ui.notifications = {
|
|||
}
|
||||
frappe.set_route('List', doctype);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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: [],
|
||||
|
|
|
|||
|
|
@ -975,12 +975,15 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
return this.data[index];
|
||||
}
|
||||
}).filter(Boolean);
|
||||
let totalRow = this.datatable.bodyRenderer.getTotalRow().reduce((row, cell) => {
|
||||
row[cell.column.id] = cell.content;
|
||||
return row;
|
||||
}, {});
|
||||
|
||||
rows.push(totalRow);
|
||||
if (this.raw_data.add_total_row) {
|
||||
let totalRow = this.datatable.bodyRenderer.getTotalRow().reduce((row, cell) => {
|
||||
row[cell.column.id] = cell.content;
|
||||
return row;
|
||||
}, {});
|
||||
|
||||
rows.push(totalRow);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -500,10 +500,9 @@ 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 => frappe.format(value, get_df(this.chart_args.y_axes[0]), { always_show_decimals: true, inline: true }, get_doc(value.doc))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -997,7 +996,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
|
|||
content: d[cdt_field(col.field)],
|
||||
editable: Boolean(name && this.is_editable(col.docfield, d)),
|
||||
format: value => {
|
||||
return frappe.format(value, col.docfield, { always_show_decimals: true });
|
||||
return frappe.format(value, col.docfield, { always_show_decimals: true }, d);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export default class WebForm extends frappe.ui.FieldGroup {
|
|||
}
|
||||
|
||||
set_field_values() {
|
||||
if (this.doc_name) this.set_values(this.doc);
|
||||
if (this.doc.name) this.set_values(this.doc);
|
||||
else return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,12 +52,13 @@ 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);
|
||||
web_form.prepare(web_form_doc, r.message.doc && web_form_doc.allow_edit === 1 ? r.message.doc : {});
|
||||
web_form.make();
|
||||
web_form.set_default_values();
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,26 +1,148 @@
|
|||
frappe.provide("frappe.integration_service")
|
||||
/* HOW-TO
|
||||
|
||||
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"
|
||||
Razorpay Payment
|
||||
|
||||
1. Include checkout script in your code
|
||||
<script type="text/javascript" src="/assets/js/checkout.min.js"></script>
|
||||
|
||||
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 = {
|
||||
"name": "<CHECKOUT MODAL TITLE>",
|
||||
"description": "<CHECKOUT MODAL DESCRIPTION>",
|
||||
"image": "<CHECKOUT MODAL LOGO>",
|
||||
"prefill": {
|
||||
"name": "<CUSTOMER NAME>",
|
||||
"email": "<CUSTOMER EMAIL>",
|
||||
"contact": "<CUSTOMER PHONE>"
|
||||
},
|
||||
"theme": {
|
||||
"color": "<MODAL COLOR>"
|
||||
},
|
||||
"doctype": "<REFERENCE DOCTYPE>",
|
||||
"docname": "<REFERENCE DOCNAME"
|
||||
};
|
||||
|
||||
razorpay = new frappe.checkout.razorpay(options)
|
||||
razorpay.on_open = () => {
|
||||
<SCRIPT TO RUN WHEN MODAL OPENS>
|
||||
}
|
||||
razorpay.on_success = () => {
|
||||
<SCRIPT TO RUN ON PAYMENT SUCCESS>
|
||||
}
|
||||
razorpay.on_fail = () => {
|
||||
<SCRIPT TO RUN ON PAYMENT FAILURE>
|
||||
}
|
||||
razorpay.init() // Creates the order and opens the modal
|
||||
}
|
||||
*/
|
||||
|
||||
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.get_key(),
|
||||
() => this.make_order(),
|
||||
() => this.prepare_options(),
|
||||
() => this.setup_handler(),
|
||||
() => this.show()
|
||||
]);
|
||||
}
|
||||
|
||||
show() {
|
||||
this.razorpay = new Razorpay(this.options);
|
||||
this.razorpay.once('ready', (response) => {
|
||||
this.on_open && this.on_open(response);
|
||||
})
|
||||
this.razorpay.open();
|
||||
}
|
||||
|
||||
get_key() {
|
||||
return new Promise(resolve => {
|
||||
frappe.call("frappe.integrations.doctype.razorpay_settings.razorpay_settings.get_api_key").then(res => {
|
||||
this.key = res.message;
|
||||
resolve(true);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
make_order() {
|
||||
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);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
order_success(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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
order_fail(response) {
|
||||
frappe.call( "frappe.integrations.doctype.razorpay_settings.razorpay_settings.order_payment_failure", {
|
||||
integration_request: this.order.integration_request,
|
||||
params: response
|
||||
})
|
||||
}
|
||||
|
||||
prepare_options() {
|
||||
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,
|
||||
"modal": this.modal
|
||||
};
|
||||
}
|
||||
|
||||
setup_handler() {
|
||||
this.options.handler = (response) => {
|
||||
if (response.error) {
|
||||
this.order_fail(response);
|
||||
this.on_fail && this.on_fail(response);
|
||||
}
|
||||
else if (response.razorpay_payment_id) {
|
||||
this.order_success(response);
|
||||
this.on_success && this.on_success(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");
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,10 @@ h4.modal-title {
|
|||
font-size: 1em;
|
||||
}
|
||||
|
||||
h5.modal-title {
|
||||
margin: 0px !important;
|
||||
}
|
||||
|
||||
.col-xs-1 { @extend .col-1; }
|
||||
.col-xs-2 { @extend .col-2; }
|
||||
.col-xs-3 { @extend .col-3; }
|
||||
|
|
|
|||
|
|
@ -21,14 +21,15 @@ frappe.ui.form.on('Energy Point Log', {
|
|||
reqd: 1
|
||||
}],
|
||||
primary_action: (values) => {
|
||||
return frappe.xcall('frappe.social.doctype.energy_point_log.energy_point_log.revert', {
|
||||
'name': frm.doc.name,
|
||||
return frm.call('revert', {
|
||||
'reason': values.reason
|
||||
}).then(revert_log => {
|
||||
}).then(res => {
|
||||
let revert_log = res.message;
|
||||
revert_dialog.hide();
|
||||
revert_dialog.clear();
|
||||
frappe.model.docinfo[frm.doc.reference_doctype][frm.doc.reference_name].energy_point_logs.unshift(revert_log);
|
||||
}).catch(() => {});
|
||||
frm.refresh();
|
||||
});
|
||||
},
|
||||
primary_action_label: __('Submit')
|
||||
});
|
||||
|
|
|
|||
|
|
@ -44,6 +44,36 @@ class EnergyPointLog(Document):
|
|||
|
||||
enqueue_create_notification(self.user, notification_doc)
|
||||
|
||||
def on_trash(self):
|
||||
if self.type == 'Revert':
|
||||
reference_log = frappe.get_doc('Energy Point Log', self.revert_of)
|
||||
reference_log.reverted = 0
|
||||
reference_log.save()
|
||||
|
||||
def revert(self, reason):
|
||||
frappe.only_for('System Manager')
|
||||
if self.type != 'Auto':
|
||||
frappe.throw(_('This document cannot be reverted'))
|
||||
|
||||
if self.get('reverted'):
|
||||
return
|
||||
|
||||
self.reverted = 1
|
||||
self.save(ignore_permissions=True)
|
||||
|
||||
revert_log = frappe.get_doc({
|
||||
'doctype': 'Energy Point Log',
|
||||
'points': -(self.points),
|
||||
'type': 'Revert',
|
||||
'user': self.user,
|
||||
'reason': reason,
|
||||
'reference_doctype': self.reference_doctype,
|
||||
'reference_name': self.reference_name,
|
||||
'revert_of': self.name
|
||||
}).insert(ignore_permissions=True)
|
||||
|
||||
return revert_log
|
||||
|
||||
def get_notification_message(doc):
|
||||
owner_name = get_fullname(doc.owner)
|
||||
points = doc.points
|
||||
|
|
@ -149,7 +179,8 @@ def check_if_log_exists(ref_doctype, ref_name, rule, user=None):
|
|||
filters = frappe._dict({
|
||||
'rule': rule,
|
||||
'reference_doctype': ref_doctype,
|
||||
'reference_name': ref_name
|
||||
'reference_name': ref_name,
|
||||
'reverted': 0
|
||||
})
|
||||
|
||||
if user:
|
||||
|
|
@ -257,32 +288,6 @@ def get_reviews(doctype, docname):
|
|||
'type': ['in', ('Appreciation', 'Criticism')],
|
||||
}, fields=['points', 'owner', 'type', 'user', 'reason', 'creation'])
|
||||
|
||||
@frappe.whitelist()
|
||||
def revert(name, reason):
|
||||
frappe.only_for('System Manager')
|
||||
doc_to_revert = frappe.get_doc('Energy Point Log', name)
|
||||
|
||||
if doc_to_revert.type != 'Auto':
|
||||
frappe.throw(_('This document cannot be reverted'))
|
||||
|
||||
if doc_to_revert.reverted: return
|
||||
|
||||
doc_to_revert.reverted = 1
|
||||
doc_to_revert.save(ignore_permissions=True)
|
||||
|
||||
revert_log = frappe.get_doc({
|
||||
'doctype': 'Energy Point Log',
|
||||
'points': -(doc_to_revert.points),
|
||||
'type': 'Revert',
|
||||
'user': doc_to_revert.user,
|
||||
'reason': reason,
|
||||
'reference_doctype': doc_to_revert.reference_doctype,
|
||||
'reference_name': doc_to_revert.reference_name,
|
||||
'revert_of': doc_to_revert.name
|
||||
}).insert(ignore_permissions=True)
|
||||
|
||||
return revert_log
|
||||
|
||||
def send_weekly_summary():
|
||||
send_summary('Weekly')
|
||||
|
||||
|
|
@ -325,5 +330,3 @@ def get_footer_message(timespan):
|
|||
return _("Stats based on last month's performance (from {0} to {1})")
|
||||
else:
|
||||
return _("Stats based on last week's performance (from {0} to {1})")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -249,6 +249,27 @@ class TestEnergyPointLog(unittest.TestCase):
|
|||
# point should not be awarded more than once for same doc (irrespective of user)
|
||||
self.assertEqual(second_user_points_after_closing_todo, second_user_points)
|
||||
|
||||
def test_allow_creation_of_new_log_if_the_previous_log_was_reverted(self):
|
||||
frappe.set_user('test@example.com')
|
||||
todo_point_rule = create_energy_point_rule_for_todo()
|
||||
energy_point_of_user = get_points('test@example.com')
|
||||
|
||||
created_todo = create_a_todo()
|
||||
|
||||
created_todo.status = 'Closed'
|
||||
created_todo.save()
|
||||
points_after_closing_todo = get_points('test@example.com')
|
||||
|
||||
log_name = frappe.db.exists('Energy Point Log', {'reference_name': created_todo.name})
|
||||
frappe.get_doc('Energy Point Log', log_name).revert('Just for test')
|
||||
points_after_reverting_todo = get_points('test@example.com')
|
||||
created_todo.save()
|
||||
points_after_saving_todo_again = get_points('test@example.com')
|
||||
|
||||
rule_points = todo_point_rule.points
|
||||
self.assertEqual(points_after_closing_todo, energy_point_of_user + rule_points)
|
||||
self.assertEqual(points_after_reverting_todo, points_after_closing_todo - rule_points)
|
||||
self.assertEqual(points_after_saving_todo_again, points_after_reverting_todo + rule_points)
|
||||
|
||||
def create_energy_point_rule_for_todo(multiplier_field=None, for_doc_event='Custom', max_points=None,
|
||||
for_assigned_users=0, field_to_check=None, apply_once=False, user_field='owner'):
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ from frappe import _
|
|||
import frappe.cache_manager
|
||||
from frappe.model.document import Document
|
||||
from frappe.social.doctype.energy_point_settings.energy_point_settings import is_energy_point_enabled
|
||||
from frappe.social.doctype.energy_point_log.energy_point_log import create_energy_points_log, revert
|
||||
from frappe.social.doctype.energy_point_log.energy_point_log import \
|
||||
create_energy_points_log
|
||||
|
||||
class EnergyPointRule(Document):
|
||||
def on_update(self):
|
||||
|
|
@ -106,7 +107,8 @@ def revert_points_for_cancelled_doc(doc):
|
|||
'type': 'Auto'
|
||||
})
|
||||
for log in energy_point_logs:
|
||||
revert(log.name, _('Reference document has been cancelled'))
|
||||
reference_log = frappe.get_doc('Energy Point Log', log.name)
|
||||
reference_log.revert(_('Reference document has been cancelled'))
|
||||
|
||||
|
||||
def get_energy_point_doctypes():
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@ def get_monthly_goal_graph_data(title, doctype, docname, goal_value_field, goal_
|
|||
if filter_str:
|
||||
doc_filter += ' and ' + filter_str if doc_filter else filter_str
|
||||
month_to_value_dict = get_monthly_results(goal_doctype, goal_field, date_field, doc_filter, aggregation)
|
||||
frappe.db.set_value(doctype, docname, goal_history_field, json.dumps(month_to_value_dict))
|
||||
|
||||
month_to_value_dict[current_month_year] = current_month_value
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ def as_json():
|
|||
def as_pdf():
|
||||
response = Response()
|
||||
response.mimetype = "application/pdf"
|
||||
encoded_filename = quote(frappe.response['filename'].replace(' ', '_'), encoding='utf-8')
|
||||
encoded_filename = quote(frappe.response['filename'].replace(' ', '_'))
|
||||
response.headers["Content-Disposition"] = ("filename=\"%s\"" % frappe.response['filename'].replace(' ', '_') + ";filename*=utf-8''%s" % encoded_filename).encode("utf-8")
|
||||
response.data = frappe.response['filecontent']
|
||||
return response
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -161,7 +161,8 @@ class UserPermissions:
|
|||
for docname in docs:
|
||||
if frappe.get_meta(docname, cached=True).allow_import == 1:
|
||||
self.can_import.append(docname)
|
||||
frappe.cache().hset("can_import", frappe.session.user, self.can_import)
|
||||
|
||||
frappe.cache().hset("can_import", frappe.session.user, self.can_import)
|
||||
|
||||
def get_defaults(self):
|
||||
import frappe.defaults
|
||||
|
|
|
|||
|
|
@ -1,528 +1,158 @@
|
|||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 1,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2013-03-28 10:35:30",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"editable_grid": 0,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"title",
|
||||
"published_on",
|
||||
"published",
|
||||
"column_break_3",
|
||||
"blog_category",
|
||||
"blogger",
|
||||
"route",
|
||||
"section_break_5",
|
||||
"blog_intro",
|
||||
"content_type",
|
||||
"content",
|
||||
"content_md",
|
||||
"content_html",
|
||||
"email_sent"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Title",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "published_on",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Published On",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Published On"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "published",
|
||||
"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": "Published",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Published"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "blog_category",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Blog Category",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Blog Category",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "blogger",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Blogger",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Blogger",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "route",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Route",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Description for listing page, in plain text, only a couple of lines. (max 140 characters)",
|
||||
"fieldname": "blog_intro",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Blog Intro",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Blog Intro"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Rich Text",
|
||||
"fieldname": "content_type",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Content Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Rich Text\nMarkdown\nHTML",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.content_type === 'Rich Text'",
|
||||
"fieldname": "content",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 1,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Content",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Content"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.content_type === 'Markdown'",
|
||||
"fieldname": "content_md",
|
||||
"fieldtype": "Markdown Editor",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Content (Markdown)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Content (Markdown)"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.content_type === 'HTML'",
|
||||
"fieldname": "content_html",
|
||||
"fieldtype": "HTML Editor",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Content (HTML)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"ignore_xss_filter": 1,
|
||||
"label": "Content (HTML)"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "email_sent",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Email Sent",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Email Sent"
|
||||
}
|
||||
],
|
||||
"has_web_view": 1,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "fa fa-quote-left",
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_published_field": "published",
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 5,
|
||||
"modified": "2019-02-09 11:27:05.619819",
|
||||
"modified": "2019-11-18 11:14:56.402471",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Blog Post",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Website Manager",
|
||||
"set_user_permissions": 1,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Blogger",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"route": "/blog",
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"title_field": "title",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
"track_changes": 1
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -132,12 +132,12 @@ $.extend(frappe, {
|
|||
|
||||
if (data._server_messages) {
|
||||
var server_messages = JSON.parse(data._server_messages || '[]');
|
||||
server_messages = $.map(server_messages, function(v) {
|
||||
server_messages.map((msg) => {
|
||||
// temp fix for messages sent as dict
|
||||
try {
|
||||
return JSON.parse(v).message;
|
||||
return JSON.parse(msg);
|
||||
} catch (e) {
|
||||
return v;
|
||||
return msg;
|
||||
}
|
||||
}).join('<br>');
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,12 @@
|
|||
{% block page_content %}
|
||||
<!-- {{ for_test }} -->
|
||||
<div style='min-height: 360px'>
|
||||
<noscript>
|
||||
<div class="text-center my-5">
|
||||
<h4>{{ _("Javascript is disabled on your browser") }}</h4>
|
||||
<p class="text-muted">{{ _("You need to enable JavaScript for your app to work.") }}<br>{{ _("To enable it follow the instructions in the following link: {0}").format("<a href='https://enable-javascript.com/'>enable-javascript.com</a></p>") }}
|
||||
</div>
|
||||
</noscript>
|
||||
<section class='for-login'>
|
||||
<div class="login-content page-card" style="margin-top: 30px;">
|
||||
<form class="form-signin form-login" role="form">
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue