Merge branch 'hotfix'
This commit is contained in:
commit
288b98ca76
9 changed files with 68 additions and 16 deletions
|
|
@ -14,7 +14,7 @@ import os, sys, importlib, inspect, json
|
|||
from .exceptions import *
|
||||
from .utils.jinja import get_jenv, get_template, render_template, get_email_from_template
|
||||
|
||||
__version__ = '10.1.42'
|
||||
__version__ = '10.1.43'
|
||||
__title__ = "Frappe Framework"
|
||||
|
||||
local = Local()
|
||||
|
|
|
|||
|
|
@ -260,6 +260,8 @@ class TestUser(unittest.TestCase):
|
|||
def test_comment_mentions(self):
|
||||
user_name = "@test.comment@example.com"
|
||||
self.assertEqual(extract_mentions(user_name)[0], "test.comment@example.com")
|
||||
user_name = "@test.comment@test-example.com"
|
||||
self.assertEqual(extract_mentions(user_name)[0], "test.comment@test-example.com")
|
||||
user_name = "Testing comment, @test-user please check."
|
||||
self.assertEqual(extract_mentions(user_name)[0], "test-user")
|
||||
user_name = "Testing comment, @test.user@example.com please check."
|
||||
|
|
|
|||
|
|
@ -901,6 +901,7 @@ def notify_admin_access_to_system_manager(login_manager=None):
|
|||
def extract_mentions(txt):
|
||||
"""Find all instances of @name in the string.
|
||||
The mentions will be separated by non-word characters or may appear at the start of the string"""
|
||||
txt = re.sub(r'(<[a-zA-Z\/][^>]*>)', '', txt)
|
||||
return re.findall(r'(?:[^\w\.\-\@]|^)@([\w\.\-\@]*)', txt)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
|
|
@ -72,6 +73,7 @@
|
|||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
|
|
@ -99,9 +101,10 @@
|
|||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
|
|
@ -129,9 +132,10 @@
|
|||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
|
|
@ -145,7 +149,7 @@
|
|||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-11-14 14:14:11.544811",
|
||||
"modified": "2018-07-20 08:23:23.737254",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Desk",
|
||||
"name": "Calendar View",
|
||||
|
|
|
|||
|
|
@ -310,9 +310,9 @@ frappe.ui.form.Timeline = Class.extend({
|
|||
// bold @mentions
|
||||
if(c.comment_type==="Comment" &&
|
||||
// avoid adding <b> tag a 2nd time
|
||||
!c.content_html.match(/(^|\W)<b>(@\w+)<\/b>/)
|
||||
!c.content_html.match(/(^|\W)<b>(@[^\s]+)<\/b>/)
|
||||
) {
|
||||
c.content_html = c.content_html.replace(/(^|\W)(@\w+)/g, "$1<b>$2</b>");
|
||||
c.content_html = c.content_html.replace(/(^|\W)(@[^\s]+)/g, "$1<b>$2</b>");
|
||||
}
|
||||
|
||||
if (this.is_communication_or_comment(c)) {
|
||||
|
|
|
|||
|
|
@ -322,7 +322,6 @@ frappe.ui.BaseList = Class.extend({
|
|||
|
||||
return frappe.call({
|
||||
method: this.opts.method || 'frappe.desk.query_builder.runquery',
|
||||
type: "GET",
|
||||
freeze: this.opts.freeze !== undefined ? this.opts.freeze : true,
|
||||
args: args,
|
||||
callback: function (r) {
|
||||
|
|
|
|||
|
|
@ -391,7 +391,7 @@ frappe.views.ReportView = frappe.ui.BaseList.extend({
|
|||
var me = this;
|
||||
var data = this.get_unique_data(this.column_info);
|
||||
|
||||
this.set_totals_row(data);
|
||||
this.set_totals_row(data, this.column_info);
|
||||
|
||||
// add sr in data
|
||||
$.each(data, function(i, v) {
|
||||
|
|
@ -617,13 +617,23 @@ frappe.views.ReportView = frappe.ui.BaseList.extend({
|
|||
});
|
||||
},
|
||||
|
||||
set_totals_row: function(data) {
|
||||
set_totals_row: function(data, columns) {
|
||||
const field_map = {};
|
||||
const numeric_fieldtypes = ['Int', 'Currency', 'Float'];
|
||||
columns.forEach(function(row) {
|
||||
if (row.docfield) {
|
||||
let r = row.docfield;
|
||||
if (numeric_fieldtypes.includes(r.fieldtype)) {
|
||||
field_map[r.fieldname] = [r.fieldtype];
|
||||
}
|
||||
}
|
||||
})
|
||||
if(this.add_totals_row) {
|
||||
var totals_row = {_totals_row: 1};
|
||||
if(data.length) {
|
||||
data.forEach(function(row, ri) {
|
||||
$.each(row, function(key, value) {
|
||||
if($.isNumeric(value)) {
|
||||
if (key in field_map) {
|
||||
totals_row[key] = (totals_row[key] || 0) + value;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -548,3 +548,37 @@ def get_site_info():
|
|||
|
||||
# dumps -> loads to prevent datatype conflicts
|
||||
return json.loads(frappe.as_json(site_info))
|
||||
|
||||
def get_db_count(*args):
|
||||
"""
|
||||
Pass a doctype or a series of doctypes to get the count of docs in them
|
||||
Parameters:
|
||||
*args: Variable length argument list of doctype names whose doc count you need
|
||||
|
||||
Returns:
|
||||
dict: A dict with the count values.
|
||||
|
||||
Example:
|
||||
via terminal:
|
||||
bench --site erpnext.local execute frappe.utils.get_db_count --args "['DocType', 'Communication']"
|
||||
"""
|
||||
db_count = {}
|
||||
for doctype in args:
|
||||
db_count[doctype] = frappe.db.count(doctype)
|
||||
|
||||
return json.loads(frappe.as_json(db_count))
|
||||
|
||||
def call(fn, *args, **kwargs):
|
||||
"""
|
||||
Pass a doctype or a series of doctypes to get the count of docs in them
|
||||
Parameters:
|
||||
fn: frappe function to be called
|
||||
|
||||
Returns:
|
||||
based on the function you call: output of the function you call
|
||||
|
||||
Example:
|
||||
via terminal:
|
||||
bench --site erpnext.local execute frappe.utils.call --args '''["frappe.get_all", "Activity Log"]''' --kwargs '''{"fields": ["user", "creation", "full_name"], "filters":{"Operation": "Login", "Status": "Success"}, "limit": "10"}'''
|
||||
"""
|
||||
return json.loads(frappe.as_json(frappe.call(fn, *args, **kwargs)))
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ from frappe.utils import scrub_urls
|
|||
from frappe import _
|
||||
from bs4 import BeautifulSoup
|
||||
from PyPDF2 import PdfFileWriter, PdfFileReader
|
||||
import re
|
||||
|
||||
def get_pdf(html, options=None, output = None):
|
||||
html = scrub_urls(html)
|
||||
|
|
@ -16,7 +17,7 @@ def get_pdf(html, options=None, output = None):
|
|||
try:
|
||||
pdfkit.from_string(html, fname, options=options or {})
|
||||
if output:
|
||||
append_pdf(PdfFileReader(file(fname,"rb")),output)
|
||||
append_pdf(PdfFileReader(fname),output)
|
||||
else:
|
||||
with open(fname, "rb") as fileobj:
|
||||
filedata = fileobj.read()
|
||||
|
|
@ -88,12 +89,13 @@ def read_options_from_html(html):
|
|||
|
||||
toggle_visible_pdf(soup)
|
||||
|
||||
# extract pdfkit options from html
|
||||
for html_id in ("margin-top", "margin-bottom", "margin-left", "margin-right", "page-size"):
|
||||
# use regex instead of soup-parser
|
||||
for attr in ("margin-top", "margin-bottom", "margin-left", "margin-right", "page-size"):
|
||||
try:
|
||||
tag = soup.find(id=html_id)
|
||||
if tag and tag.contents:
|
||||
options[html_id] = tag.contents
|
||||
pattern = re.compile(r"(\.print-format)([\S|\s][^}]*?)(" + str(attr) + r":)(.+)(mm;)")
|
||||
match = pattern.findall(html)
|
||||
if match:
|
||||
options[attr] = str(match[-1][3]).strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue