Merge branch 'develop' of https://github.com/frappe/frappe into custom_append_to
This commit is contained in:
commit
092dcde236
20 changed files with 124 additions and 44 deletions
|
|
@ -91,5 +91,6 @@ install:
|
|||
- bench build --app frappe
|
||||
|
||||
after_script:
|
||||
- pip install coverage==4.5.4
|
||||
- pip install python-coveralls
|
||||
- coveralls -b apps/frappe -d ../../sites/.coverage
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<tbody>
|
||||
{% for j in jobs %}
|
||||
<tr>
|
||||
<td><span class="indicator {{ j.color }}" title="{{ j.get_status() }}">{{ j.queue.split(".").slice(-1)[0] }}</span></td>
|
||||
<td><span class="indicator {{ j.color }}" title="{{ j.status }}">{{ j.queue.split(".").slice(-1)[0] }}</span></td>
|
||||
<td style="overflow: auto;">
|
||||
<div>
|
||||
{{ frappe.utils.encode_tags(j.job_name) }}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,14 @@ frappe.ui.form.on("Customize Form", {
|
|||
};
|
||||
});
|
||||
|
||||
frm.set_query("default_print_format", function() {
|
||||
return {
|
||||
filters: {
|
||||
'print_format_type': ['!=', 'JS']
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(frm.wrapper).on("grid-row-render", function(e, grid_row) {
|
||||
if(grid_row.doc && grid_row.doc.fieldtype=="Section Break") {
|
||||
$(grid_row.row).css({"font-weight": "bold"});
|
||||
|
|
|
|||
|
|
@ -114,9 +114,8 @@ frappe.ui.form.on('Dashboard Chart', {
|
|||
} else {
|
||||
// standard filters
|
||||
if (frm.doc.document_type) {
|
||||
// allow all link and select fields as filters
|
||||
frm.chart_filters = [];
|
||||
frappe.model.with_doctype(frm.doc.document_type, () => {
|
||||
frm.chart_filters = [];
|
||||
frappe.get_meta(frm.doc.document_type).fields.map(df => {
|
||||
if (['Link', 'Select'].includes(df.fieldtype)) {
|
||||
let _df = copy_dict(df);
|
||||
|
|
@ -131,8 +130,8 @@ frappe.ui.form.on('Dashboard Chart', {
|
|||
|
||||
frm.chart_filters.push(_df);
|
||||
}
|
||||
frm.trigger('render_filters_table');
|
||||
});
|
||||
frm.trigger('render_filters_table');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -158,7 +157,7 @@ frappe.ui.form.on('Dashboard Chart', {
|
|||
|
||||
let filters = JSON.parse(frm.doc.filters_json || '{}');
|
||||
var filters_set = false;
|
||||
fields.map( f => {
|
||||
fields.map(f => {
|
||||
if (filters[f.fieldname]) {
|
||||
const filter_row = $(`<tr><td>${f.label}</td><td>${filters[f.fieldname] || ""}</td></tr>`);
|
||||
table.find('tbody').append(filter_row);
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ def get_prepared_report_result(report, filters, dn="", user=None):
|
|||
"status": "Completed",
|
||||
"filters": json.dumps(filters),
|
||||
"owner": user,
|
||||
"report_name": report.custom_report or report.report_name
|
||||
"report_name": report.get('custom_report') or report.get('report_name')
|
||||
},
|
||||
order_by = 'creation desc'
|
||||
)
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class StripeSettings(Document):
|
|||
def create_charge_on_stripe(self):
|
||||
import stripe
|
||||
try:
|
||||
charge = stripe.Charge.create(amount=cint(flt(self.data.amount)*100), currency=self.data.currency, source=self.data.stripe_token_id, description=self.data.description)
|
||||
charge = stripe.Charge.create(amount=cint(flt(self.data.amount)*100), currency=self.data.currency, source=self.data.stripe_token_id, description=self.data.description, receipt_email=self.data.payer_email)
|
||||
|
||||
if charge.captured == True:
|
||||
self.integration_request.db_set('status', 'Completed', update_modified=False)
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ frappe.ui.form.on('Webhook', {
|
|||
|
||||
webhook_doctype: (frm) => {
|
||||
frappe.webhook.set_fieldname_select(frm);
|
||||
},
|
||||
|
||||
enable_security: (frm) => {
|
||||
frm.toggle_reqd('webhook_secret', frm.doc.enable_security);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
"request_url",
|
||||
"cb_webhook",
|
||||
"request_structure",
|
||||
"sb_security",
|
||||
"enable_security",
|
||||
"webhook_secret",
|
||||
"sb_webhook_headers",
|
||||
"webhook_headers",
|
||||
"sb_webhook_data",
|
||||
|
|
@ -127,10 +130,27 @@
|
|||
"fieldtype": "Select",
|
||||
"label": "Naming Series",
|
||||
"options": "\nHOOK-.####"
|
||||
},
|
||||
{
|
||||
"fieldname": "sb_security",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Webhook Security"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "enable_security",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enable Security"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.enable_security == 1",
|
||||
"fieldname": "webhook_secret",
|
||||
"fieldtype": "Password",
|
||||
"label": "Webhook Secret"
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-01-06 02:51:07.997566",
|
||||
"modified": "2020-01-13 01:53:04.459968",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Integrations",
|
||||
"name": "Webhook",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import base64
|
||||
import datetime
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
from time import sleep
|
||||
|
||||
|
|
@ -16,6 +19,8 @@ from frappe import _
|
|||
from frappe.model.document import Document
|
||||
from frappe.utils.jinja import validate_template
|
||||
|
||||
WEBHOOK_SECRET_HEADER = "X-Frappe-Webhook-Signature"
|
||||
|
||||
|
||||
class Webhook(Document):
|
||||
def validate(self):
|
||||
|
|
@ -94,10 +99,23 @@ def enqueue_webhook(doc, webhook):
|
|||
|
||||
def get_webhook_headers(doc, webhook):
|
||||
headers = {}
|
||||
|
||||
if webhook.enable_security:
|
||||
data = get_webhook_data(doc, webhook)
|
||||
signature = base64.b64encode(
|
||||
hmac.new(
|
||||
webhook.get_password("webhook_secret").encode("utf8"),
|
||||
json.dumps(data).encode("utf8"),
|
||||
hashlib.sha256
|
||||
).digest()
|
||||
)
|
||||
headers[WEBHOOK_SECRET_HEADER] = signature
|
||||
|
||||
if webhook.webhook_headers:
|
||||
for h in webhook.webhook_headers:
|
||||
if h.get("key") and h.get("value"):
|
||||
headers[h.get("key")] = h.get("value")
|
||||
|
||||
return headers
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ def login_via_office365(code, state):
|
|||
def login_via_salesforce(code, state):
|
||||
login_via_oauth2("salesforce", code, state, decoder=decoder_compat)
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def login_via_fairlogin(code, state):
|
||||
login_via_oauth2("fairlogin", code, state, decoder=decoder_compat)
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def custom(code, state):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import frappe
|
|||
|
||||
def execute():
|
||||
if frappe.db.table_exists('Prepared Report'):
|
||||
frappe.reload_doc("core", "doctype", "prepared_doctype")
|
||||
frappe.reload_doc("core", "doctype", "prepared_report")
|
||||
prepared_reports = frappe.get_all("Prepared Report")
|
||||
for report in prepared_reports:
|
||||
frappe.delete_doc("Prepared Report", report.name)
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@ frappe.Application = Class.extend({
|
|||
// Iterate over changelog
|
||||
var change_log_dialog = frappe.msgprint({
|
||||
message: frappe.render_template("change_log", {"change_log": change_log}),
|
||||
title: __("Updated To New Version 🎉"),
|
||||
title: __("Updated To A New Version 🎉"),
|
||||
wide: true,
|
||||
scroll: true
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlCode.extend({
|
||||
frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({
|
||||
horizontal: false,
|
||||
|
||||
make_wrapper() {
|
||||
// Create the elements for map area
|
||||
this._super();
|
||||
|
|
|
|||
|
|
@ -371,6 +371,10 @@ frappe.ui.form.Timeline = class Timeline {
|
|||
c.sender = c.sender.split("<")[1].split(">")[0];
|
||||
}
|
||||
|
||||
if (!c.doctype && ['Comment', 'Communication'].includes(c.communication_type)) {
|
||||
c.doctype = c.communication_type;
|
||||
}
|
||||
|
||||
c.user_info = frappe.user_info(c.sender);
|
||||
|
||||
c["delete"] = "";
|
||||
|
|
|
|||
|
|
@ -65,26 +65,22 @@ export default class Grid {
|
|||
<div class="small form-clickable-section grid-footer">
|
||||
<div class="row">
|
||||
<div class="col-sm-5 grid-buttons">
|
||||
<button type="reset"
|
||||
class="btn btn-xs btn-danger grid-remove-rows hidden"
|
||||
<button class="btn btn-xs btn-danger grid-remove-rows hidden"
|
||||
style="margin-right: 4px;"
|
||||
data-action="delete_rows">
|
||||
${__("Delete")}
|
||||
</button>
|
||||
<button type="reset"
|
||||
class="btn btn-xs btn-danger grid-remove-all-rows hidden"
|
||||
<button class="btn btn-xs btn-danger grid-remove-all-rows hidden"
|
||||
style="margin-right: 4px;"
|
||||
data-action="delete_all_rows">
|
||||
${__("Delete All")}
|
||||
</button>
|
||||
<button type="reset"
|
||||
class="grid-add-multiple-rows btn btn-xs btn-default hidden"
|
||||
<button class="grid-add-multiple-rows btn btn-xs btn-default hidden"
|
||||
style="margin-right: 4px;">
|
||||
${__("Add Multiple")}</a>
|
||||
</button>
|
||||
<!-- hack to allow firefox include this in tabs -->
|
||||
<button type="reset"
|
||||
class="btn btn-xs btn-default grid-add-row">
|
||||
<button class="btn btn-xs btn-default grid-add-row">
|
||||
${__("Add Row")}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -267,19 +267,24 @@ frappe.ui.form.Toolbar = Class.extend({
|
|||
});
|
||||
}
|
||||
|
||||
if(frappe.user_roles.includes("System Manager") && me.frm.meta.issingle === 0) {
|
||||
this.page.add_menu_item(__("Customize"), function() {
|
||||
if (frappe.user_roles.includes("System Manager") && me.frm.meta.issingle === 0) {
|
||||
let is_doctype_form = me.frm.doctype === 'DocType';
|
||||
let doctype = is_doctype_form ? me.frm.docname : me.frm.doctype;
|
||||
let is_doctype_custom = is_doctype_form ? me.frm.doc.custom : false;
|
||||
|
||||
if (me.frm.meta && me.frm.meta.custom) {
|
||||
frappe.set_route('Form', 'DocType', me.frm.doctype);
|
||||
} else {
|
||||
frappe.set_route('Form', 'Customize Form', {
|
||||
doc_type: me.frm.doctype
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
if (doctype != 'DocType' && !is_doctype_custom) {
|
||||
this.page.add_menu_item(__("Customize"), function() {
|
||||
if (me.frm.meta && me.frm.meta.custom) {
|
||||
frappe.set_route('Form', 'DocType', doctype);
|
||||
} else {
|
||||
frappe.set_route('Form', 'Customize Form', {
|
||||
doc_type: doctype
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
if (frappe.boot.developer_mode===1) {
|
||||
if (frappe.boot.developer_mode===1 && !is_doctype_form) {
|
||||
// edit doctype
|
||||
this.page.add_menu_item(__("Edit DocType"), function() {
|
||||
frappe.set_route('Form', 'DocType', me.frm.doctype);
|
||||
|
|
|
|||
|
|
@ -81,7 +81,11 @@ frappe.ui.GroupBy = class {
|
|||
}
|
||||
|
||||
apply_settings(settings) {
|
||||
this.groupby_select.val(settings.group_by);
|
||||
|
||||
// Extract fieldname from `tabdoctype`.`fieldname`
|
||||
let group_by_fieldname = settings.group_by.split('.')[1].replace('`', '');
|
||||
|
||||
this.groupby_select.val(group_by_fieldname);
|
||||
this.aggregate_function_select.val(settings.aggregate_function);
|
||||
this.show_hide_aggregate_on();
|
||||
this.aggregate_on_select.val(settings.aggregate_on);
|
||||
|
|
|
|||
|
|
@ -86,7 +86,11 @@ export default class WebForm extends frappe.ui.FieldGroup {
|
|||
}
|
||||
|
||||
setup_delete_button() {
|
||||
this.add_button_to_header("Delete", "danger", () => this.delete());
|
||||
this.add_button_to_header(
|
||||
'<i class="fa fa-trash" aria-hidden="true"></i>',
|
||||
"light",
|
||||
() => this.delete()
|
||||
);
|
||||
}
|
||||
|
||||
setup_print_button() {
|
||||
|
|
|
|||
|
|
@ -713,6 +713,7 @@ li.user-progress {
|
|||
height: 60px;
|
||||
width: 60px;
|
||||
background-color: #fafbfc;
|
||||
overflow: hidden;
|
||||
|
||||
.flex-text {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ def main(app=None, module=None, doctype=None, verbose=False, tests=(),
|
|||
|
||||
xmloutput_fh = None
|
||||
if junit_xml_output:
|
||||
xmloutput_fh = open(junit_xml_output, 'w')
|
||||
xmloutput_fh = open(junit_xml_output, 'wb')
|
||||
unittest_runner = xmlrunner_wrapper(xmloutput_fh)
|
||||
else:
|
||||
unittest_runner = unittest.TextTestRunner
|
||||
|
|
@ -68,11 +68,11 @@ def main(app=None, module=None, doctype=None, verbose=False, tests=(),
|
|||
frappe.get_attr(fn)()
|
||||
|
||||
if doctype:
|
||||
ret = run_tests_for_doctype(doctype, verbose, tests, force, profile)
|
||||
ret = run_tests_for_doctype(doctype, verbose, tests, force, profile, junit_xml_output=junit_xml_output)
|
||||
elif module:
|
||||
ret = run_tests_for_module(module, verbose, tests, profile)
|
||||
ret = run_tests_for_module(module, verbose, tests, profile, junit_xml_output=junit_xml_output)
|
||||
else:
|
||||
ret = run_all_tests(app, verbose, profile, ui_tests, failfast=failfast)
|
||||
ret = run_all_tests(app, verbose, profile, ui_tests, failfast=failfast, junit_xml_output=junit_xml_output)
|
||||
|
||||
if frappe.db: frappe.db.commit()
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ class TimeLoggingTestResult(unittest.TextTestResult):
|
|||
super(TimeLoggingTestResult, self).addSuccess(test)
|
||||
|
||||
|
||||
def run_all_tests(app=None, verbose=False, profile=False, ui_tests=False, failfast=False):
|
||||
def run_all_tests(app=None, verbose=False, profile=False, ui_tests=False, failfast=False, junit_xml_output=False):
|
||||
import os
|
||||
|
||||
apps = [app] if app else frappe.get_installed_apps()
|
||||
|
|
@ -130,11 +130,16 @@ def run_all_tests(app=None, verbose=False, profile=False, ui_tests=False, failfa
|
|||
_add_test(app, path, filename, verbose,
|
||||
test_suite, ui_tests)
|
||||
|
||||
if junit_xml_output:
|
||||
runner = unittest_runner(verbosity=1+(verbose and 1 or 0), failfast=failfast)
|
||||
else:
|
||||
runner = unittest_runner(resultclass=TimeLoggingTestResult, verbosity=1+(verbose and 1 or 0), failfast=failfast)
|
||||
|
||||
if profile:
|
||||
pr = cProfile.Profile()
|
||||
pr.enable()
|
||||
|
||||
out = unittest_runner(resultclass=TimeLoggingTestResult, verbosity=1+(verbose and 1 or 0), failfast=failfast).run(test_suite)
|
||||
out = runner.run(test_suite)
|
||||
|
||||
if profile:
|
||||
pr.disable()
|
||||
|
|
@ -145,7 +150,7 @@ def run_all_tests(app=None, verbose=False, profile=False, ui_tests=False, failfa
|
|||
|
||||
return out
|
||||
|
||||
def run_tests_for_doctype(doctypes, verbose=False, tests=(), force=False, profile=False):
|
||||
def run_tests_for_doctype(doctypes, verbose=False, tests=(), force=False, profile=False, junit_xml_output=False):
|
||||
modules = []
|
||||
if not isinstance(doctypes, (list, tuple)):
|
||||
doctypes = [doctypes]
|
||||
|
|
@ -163,17 +168,17 @@ def run_tests_for_doctype(doctypes, verbose=False, tests=(), force=False, profil
|
|||
make_test_records(doctype, verbose=verbose, force=force)
|
||||
modules.append(importlib.import_module(test_module))
|
||||
|
||||
return _run_unittest(modules, verbose=verbose, tests=tests, profile=profile)
|
||||
return _run_unittest(modules, verbose=verbose, tests=tests, profile=profile, junit_xml_output=junit_xml_output)
|
||||
|
||||
def run_tests_for_module(module, verbose=False, tests=(), profile=False):
|
||||
def run_tests_for_module(module, verbose=False, tests=(), profile=False, junit_xml_output=False):
|
||||
module = importlib.import_module(module)
|
||||
if hasattr(module, "test_dependencies"):
|
||||
for doctype in module.test_dependencies:
|
||||
make_test_records(doctype, verbose=verbose)
|
||||
|
||||
return _run_unittest(module, verbose=verbose, tests=tests, profile=profile)
|
||||
return _run_unittest(module, verbose=verbose, tests=tests, profile=profile, junit_xml_output=junit_xml_output)
|
||||
|
||||
def _run_unittest(modules, verbose=False, tests=(), profile=False):
|
||||
def _run_unittest(modules, verbose=False, tests=(), profile=False, junit_xml_output=False):
|
||||
test_suite = unittest.TestSuite()
|
||||
|
||||
if not isinstance(modules, (list, tuple)):
|
||||
|
|
@ -189,13 +194,18 @@ def _run_unittest(modules, verbose=False, tests=(), profile=False):
|
|||
else:
|
||||
test_suite.addTest(module_test_cases)
|
||||
|
||||
if junit_xml_output:
|
||||
runner = unittest_runner(verbosity=1+(verbose and 1 or 0))
|
||||
else:
|
||||
runner = unittest_runner(resultclass=TimeLoggingTestResult, verbosity=1+(verbose and 1 or 0))
|
||||
|
||||
if profile:
|
||||
pr = cProfile.Profile()
|
||||
pr.enable()
|
||||
|
||||
frappe.flags.tests_verbose = verbose
|
||||
|
||||
out = unittest_runner(verbosity=1+(verbose and 1 or 0)).run(test_suite)
|
||||
out = runner.run(test_suite)
|
||||
|
||||
|
||||
if profile:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue