@@ -226,19 +226,23 @@ def get_request_header(key, default=None): | |||
return request.headers.get(key, default) | |||
def sendmail(recipients=(), sender="", subject="No Subject", message="No Message", | |||
as_markdown=False, bulk=False): | |||
as_markdown=False, bulk=False, ref_doctype=None, ref_docname=None, | |||
add_unsubscribe_link=False): | |||
if bulk: | |||
import frappe.utils.email_lib.bulk | |||
frappe.utils.email_lib.bulk.send(recipients=recipients, sender=sender, | |||
subject=subject, message=message, add_unsubscribe_link=False) | |||
subject=subject, message=message, ref_doctype = ref_doctype, | |||
ref_docname = ref_docname, add_unsubscribe_link=add_unsubscribe_link) | |||
else: | |||
import frappe.utils.email_lib | |||
if as_markdown: | |||
frappe.utils.email_lib.sendmail_md(recipients, sender=sender, subject=subject, msg=message) | |||
frappe.utils.email_lib.sendmail_md(recipients, sender=sender, | |||
subject=subject, msg=message) | |||
else: | |||
frappe.utils.email_lib.sendmail(recipients, sender=sender, subject=subject, msg=message) | |||
frappe.utils.email_lib.sendmail(recipients, sender=sender, | |||
subject=subject, msg=message) | |||
logger = None | |||
whitelisted = [] | |||
@@ -772,7 +772,7 @@ def smtp_debug_server(): | |||
os.execv(python, [python, '-m', "smtpd", "-n", "-c", "DebuggingServer", "localhost:25"]) | |||
@cmd | |||
def run_tests(app=None, module=None, doctype=None, verbose=False, tests=(), driver=None): | |||
def run_tests(app=None, module=None, doctype=None, verbose=False, tests=(), driver=None, force=False): | |||
import frappe.test_runner | |||
from frappe.utils import sel | |||
@@ -781,7 +781,7 @@ def run_tests(app=None, module=None, doctype=None, verbose=False, tests=(), driv | |||
ret = 1 | |||
try: | |||
ret = frappe.test_runner.main(app and app[0], module and module[0], doctype and doctype[0], verbose, | |||
tests=tests) | |||
tests=tests, force=force) | |||
if len(ret.failures) == 0 and len(ret.errors) == 0: | |||
ret = 0 | |||
finally: | |||
@@ -121,6 +121,11 @@ def get_data(): | |||
"name": "Outgoing Email Settings", | |||
"description": _("Set outgoing mail server.") | |||
}, | |||
{ | |||
"type": "doctype", | |||
"name": "Email Alert", | |||
"description": _("Setup Email Alert based on various criteria.") | |||
}, | |||
{ | |||
"type": "doctype", | |||
"name": "Standard Reply", | |||
@@ -1,22 +1,25 @@ | |||
{ | |||
"autoname": "CWR/.#####", | |||
"creation": "2012-08-08 10:40:11.000000", | |||
"creation": "2012-08-08 10:40:11", | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"fields": [ | |||
{ | |||
"fieldname": "comment", | |||
"fieldtype": "Text", | |||
"in_list_view": 1, | |||
"label": "Comment", | |||
"no_copy": 0, | |||
"oldfieldname": "comment", | |||
"oldfieldtype": "Text", | |||
"permlevel": 0, | |||
"reqd": 1, | |||
"search_index": 0 | |||
}, | |||
{ | |||
"fieldname": "comment_by", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Comment By", | |||
"no_copy": 0, | |||
"oldfieldname": "comment_by", | |||
@@ -27,6 +30,7 @@ | |||
{ | |||
"fieldname": "comment_by_fullname", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Comment By Fullname", | |||
"no_copy": 0, | |||
"oldfieldname": "comment_by_fullname", | |||
@@ -37,6 +41,7 @@ | |||
{ | |||
"fieldname": "comment_date", | |||
"fieldtype": "Date", | |||
"in_list_view": 1, | |||
"label": "Comment Date", | |||
"no_copy": 0, | |||
"oldfieldname": "comment_date", | |||
@@ -47,6 +52,7 @@ | |||
{ | |||
"fieldname": "comment_time", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Comment Time", | |||
"no_copy": 0, | |||
"oldfieldname": "comment_time", | |||
@@ -94,7 +100,7 @@ | |||
"icon": "icon-comments", | |||
"idx": 1, | |||
"issingle": 0, | |||
"modified": "2014-01-24 13:00:20.000000", | |||
"modified": "2014-07-14 12:14:08.315217", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "Comment", | |||
@@ -0,0 +1,6 @@ | |||
[ | |||
{ | |||
"doctype": "Comment", | |||
"name":"_Test Comment 1", | |||
} | |||
] |
@@ -1,4 +1,4 @@ | |||
# Copyright (c) 2013, {app_publisher} | |||
# Copyright (c) 2013, {app_publisher} and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
@@ -6,4 +6,4 @@ import frappe | |||
from frappe.model.document import Document | |||
class {classname}(Document): | |||
pass | |||
pass |
@@ -0,0 +1,10 @@ | |||
# Copyright (c) 2013, {app_publisher} and Contributors | |||
# See license.txt | |||
import frappe | |||
import unittest | |||
test_records = frappe.get_test_records('{doctype}') | |||
class Test{classname}(unittest.TestCase): | |||
pass |
@@ -0,0 +1,6 @@ | |||
[ | |||
{{ | |||
"doctype": "{doctype}", | |||
"name":"_Test {doctype} 1", | |||
}} | |||
] |
@@ -145,20 +145,24 @@ class DocType(Document): | |||
def make_controller_template(self): | |||
from frappe.modules import get_doc_path, get_module_path, scrub | |||
pypath = os.path.join(get_doc_path(self.module, | |||
self.doctype, self.name), scrub(self.name) + '.py') | |||
if not os.path.exists(pypath): | |||
# get app publisher for copyright | |||
app = frappe.local.module_app[frappe.scrub(self.module)] | |||
if not app: | |||
frappe.throw(_("App not found")) | |||
app_publisher = frappe.get_hooks(hook="app_publisher", app_name=app)[0] | |||
with open(pypath, 'w') as pyfile: | |||
with open(os.path.join(get_module_path("core"), "doctype", "doctype", | |||
"doctype_template.py"), 'r') as srcfile: | |||
pyfile.write(srcfile.read().format(app_publisher=app_publisher, classname=self.name.replace(" ", ""))) | |||
target_path = get_doc_path(self.module, self.doctype, self.name) | |||
app = frappe.local.module_app[scrub(self.module)] | |||
if not app: | |||
frappe.throw(_("App not found")) | |||
app_publisher = frappe.get_hooks(hook="app_publisher", app_name=app)[0] | |||
for template in ["controller.py", "test_controller.py", "test_records.json"]: | |||
template_name = template.replace("controller", scrub(self.name)) | |||
target_file_path = os.path.join(target_path, template_name) | |||
if not os.path.exists(target_file_path): | |||
with open(target_file_path, 'w') as target: | |||
with open(os.path.join(get_module_path("core"), "doctype", "doctype", | |||
"boilerplate", template), 'r') as source: | |||
target.write(source.read().format(app_publisher=app_publisher, | |||
classname=self.name.replace(" ", ""), doctype=self.name)) | |||
def make_amendable(self): | |||
""" | |||
@@ -3,14 +3,23 @@ frappe.email_alert = { | |||
// get the doctype to update fields | |||
frappe.model.with_doctype(frm.doc.document_type, function() { | |||
frm._doctype_fields = $.map(frappe.get_doc("DocType", frm.doc.document_type).fields, | |||
var fields = frappe.get_doc("DocType", frm.doc.document_type).fields; | |||
var options = $.map(fields, | |||
function(d) { return in_list(frappe.model.no_value_type, d.fieldtype) ? | |||
null : d.fieldname; }); | |||
var options = "\n" + frm._doctype_fields.join("\n"); | |||
options = "\n" + options.join("\n"); | |||
// set value changed options | |||
frm.set_df_property("value_changed", "options", options); | |||
// set date changed options | |||
frm.set_df_property("date_changed", "options", $.map(fields, | |||
function(d) { return (d.fieldtype=="Date" || d.fieldtype=="Datetime") ? | |||
d.fieldname : null; })); | |||
// set email recipient options | |||
frappe.meta.get_docfield("Email Alert Recipient", "email_by_document_field", | |||
frm.doc.name).options = options; | |||
@@ -19,9 +28,9 @@ frappe.email_alert = { | |||
} | |||
frappe.ui.form.on("Email Alert", "refresh", function(frm) { | |||
frappe.email_alert.setup_fieldname_select(frm) | |||
frappe.email_alert.setup_fieldname_select(frm); | |||
}); | |||
frappe.ui.form.on("Email Alert", "document_type", function(frm) { | |||
frappe.email_alert.setup_fieldname_select(frm) | |||
frappe.email_alert.setup_fieldname_select(frm); | |||
}); |
@@ -26,7 +26,8 @@ | |||
"label": "Document Type", | |||
"options": "DocType", | |||
"permlevel": 0, | |||
"reqd": 1 | |||
"reqd": 1, | |||
"search_index": 1 | |||
}, | |||
{ | |||
"fieldname": "event", | |||
@@ -35,16 +36,27 @@ | |||
"label": "Send Alert On", | |||
"options": "\nNew\nSave\nSubmit\nCancel\nDate Change\nValue Change", | |||
"permlevel": 0, | |||
"reqd": 1 | |||
"reqd": 1, | |||
"search_index": 1 | |||
}, | |||
{ | |||
"depends_on": "eval:doc.event==\"Date Change\"", | |||
"description": "Send alert if date matches this field's value", | |||
"fieldname": "date_changed", | |||
"fieldtype": "Select", | |||
"label": "Date Changed", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"depends_on": "eval:doc.event==\"Value Change\"", | |||
"description": "Send alert if this field's value changes", | |||
"fieldname": "value_changed", | |||
"fieldtype": "Select", | |||
"label": "Value Changed", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"depends_on": "", | |||
"description": "Optional: The alert will be sent if this expression is true", | |||
"fieldname": "condition", | |||
"fieldtype": "Data", | |||
@@ -99,7 +111,7 @@ | |||
} | |||
], | |||
"icon": "icon-envelope", | |||
"modified": "2014-07-11 17:57:11.471260", | |||
"modified": "2014-07-14 12:55:10.467991", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "Email Alert", | |||
@@ -3,7 +3,88 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe import _ | |||
from frappe.model.document import Document | |||
from frappe.utils import validate_email_add | |||
class EmailAlert(Document): | |||
pass | |||
def validate(self): | |||
if self.event=="Date Changed" and not self.date_changed: | |||
frappe.throw(_("Please specify which date field must be checked")) | |||
if self.event=="Value Changed" and not self.value_changed: | |||
frappe.throw(_("Please specify which value field must be checked")) | |||
def trigger_daily_alerts(): | |||
trigger_email_alerts(None, "Date Change") | |||
def trigger_email_alerts(doc, method=None): | |||
if method=="Date Change": | |||
for alert in frappe.db.sql_list("""select name from `tabEmail Alert` | |||
where event='Date Change'"""): | |||
alert = frappe.get_doc("Email Alert", alert) | |||
for name in frappe.db.sql_list("""select name from `tab%s` where | |||
DATE(%s) = CURDATE()""" % (alert.document_type, alert.date_changed)): | |||
evaluate_alert(frappe.get_doc(alert.document_type, name), | |||
alert, "Date Change") | |||
else: | |||
if method in ("on_update", "validate") and doc.get("__in_insert"): | |||
# don't call email alerts multiple times for inserts | |||
# on insert only "New" type alert must be called | |||
return | |||
eevent = { | |||
"on_update": "Save", | |||
"after_insert": "New", | |||
"validate": "Value Change", | |||
"on_submit": "Submit", | |||
"on_cancel": "Cancel", | |||
}[method] | |||
for alert in frappe.db.sql_list("""select name from `tabEmail Alert` | |||
where document_type=%s and event=%s""", (doc.doctype, eevent)): | |||
evaluate_alert(doc, alert, eevent) | |||
def evaluate_alert(doc, alert, event): | |||
if isinstance(alert, basestring): | |||
alert = frappe.get_doc("Email Alert", alert) | |||
if alert.condition: | |||
if not eval(alert.condition): | |||
return | |||
if event=="Value Change" and not doc.is_new(): | |||
if doc.get(alert.value_changed) == frappe.db.get_value(doc.doctype, | |||
doc.name, alert.value_changed): | |||
return # value not changed | |||
for recipient in alert.email_alert_recipients: | |||
recipients = [] | |||
if recipient.condition: | |||
if not eval(recipient.condition): | |||
continue | |||
if recipient.email_by_document_field: | |||
if validate_email_add(doc.get(recipient.email_by_document_field)): | |||
recipients.append(doc.get(recipient.email_by_document_field)) | |||
# else: | |||
# print "invalid email" | |||
if recipient.cc: | |||
recipient.cc = recipient.cc.replace(",", "\n") | |||
recipients = recipients + recipient.cc.split("\n") | |||
if not recipients: | |||
return | |||
template = alert.message + footer | |||
# send alert | |||
frappe.sendmail(recipients=recipients, subject=alert.subject, | |||
message= frappe.render_template(template, {"doc": doc, "alert":alert}), | |||
bulk=True, ref_doctype = doc.doctype, ref_docname = doc.name) | |||
footer = """<div style='margin-top: 20px; font-size: 80%; color: #888'> | |||
This Email Alert {{alert.name}} was autogenerated for | |||
{{ doc.doctype }} <a href="/desk#Form/{{doc.doctype}}/{{doc.name}}">{{doc.name}}</a>. | |||
To update, modify it, go to Setup > Email > <a href="/desk#List/Email Alert">Email Alert</a> | |||
""" |
@@ -0,0 +1,97 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# See license.txt | |||
import frappe, frappe.utils, frappe.utils.scheduler | |||
import unittest | |||
test_records = frappe.get_test_records('Email Alert') | |||
class TestEmailAlert(unittest.TestCase): | |||
def setUp(self): | |||
frappe.db.sql("""delete from `tabBulk Email`""") | |||
def test_new_and_save(self): | |||
frappe.set_user("test1@example.com") | |||
comment = frappe.new_doc("Comment") | |||
comment.comment = "test" | |||
comment.insert(ignore_permissions=True) | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"ref_doctype": "Comment", | |||
"ref_docname": comment.name, "status":"Not Sent"})) | |||
frappe.db.sql("""delete from `tabBulk Email`""") | |||
comment.description = "test" | |||
comment.save() | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"ref_doctype": "Comment", | |||
"ref_docname": comment.name, "status":"Not Sent"})) | |||
def test_condition(self): | |||
frappe.set_user("test1@example.com") | |||
event = frappe.new_doc("Event") | |||
event.subject = "test", | |||
event.event_type = "Private" | |||
event.starts_on = "2014-06-06 12:00:00" | |||
event.insert() | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
event.event_type = "Public" | |||
event.save() | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
def test_value_changed(self): | |||
frappe.set_user("test1@example.com") | |||
event = frappe.new_doc("Event") | |||
event.subject = "test", | |||
event.event_type = "Private" | |||
event.starts_on = "2014-06-06 12:00:00" | |||
event.insert() | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
event.subject = "test 1" | |||
event.save() | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
event.description = "test" | |||
event.save() | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
def test_date_changed(self): | |||
frappe.set_user("test1@example.com") | |||
event = frappe.new_doc("Event") | |||
event.subject = "test", | |||
event.event_type = "Private" | |||
event.starts_on = "2014-01-01 12:00:00" | |||
event.insert() | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
frappe.utils.scheduler.trigger(frappe.local.site, "daily", now=True) | |||
# not today, so no alert | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
event.starts_on = frappe.utils.now() | |||
event.save() | |||
self.assertFalse(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) | |||
frappe.utils.scheduler.trigger(frappe.local.site, "daily", now=True) | |||
# today so show alert | |||
self.assertTrue(frappe.db.get_value("Bulk Email", {"ref_doctype": "Event", | |||
"ref_docname": event.name, "status":"Not Sent"})) |
@@ -0,0 +1,55 @@ | |||
[ | |||
{ | |||
"doctype": "Email Alert", | |||
"subject":"_Test Email Alert 1", | |||
"document_type": "Comment", | |||
"event": "New", | |||
"message": "New comment {{ doc.comment }} created", | |||
"email_alert_recipients": [ | |||
{ "email_by_document_field": "owner" } | |||
] | |||
}, | |||
{ | |||
"doctype": "Email Alert", | |||
"subject":"_Test Email Alert 2", | |||
"document_type": "Comment", | |||
"event": "Save", | |||
"message": "New comment {{ doc.comment }} saved", | |||
"email_alert_recipients": [ | |||
{ "email_by_document_field": "owner" } | |||
] | |||
}, | |||
{ | |||
"doctype": "Email Alert", | |||
"subject":"_Test Email Alert 3", | |||
"document_type": "Event", | |||
"event": "Save", | |||
"condition": "doc.event_type=='Public'", | |||
"message": "A new public event {{ doc.subject }} on {{ doc.starts_on }} is created", | |||
"email_alert_recipients": [ | |||
{ "email_by_document_field": "owner" } | |||
] | |||
}, | |||
{ | |||
"doctype": "Email Alert", | |||
"subject":"_Test Email Alert 4", | |||
"document_type": "Event", | |||
"event": "Value Change", | |||
"value_changed": "description", | |||
"message": "Description changed", | |||
"email_alert_recipients": [ | |||
{ "email_by_document_field": "owner" } | |||
] | |||
}, | |||
{ | |||
"doctype": "Email Alert", | |||
"subject":"_Test Email Alert 5", | |||
"document_type": "Event", | |||
"event": "Date Change", | |||
"date_changed": "starts_on", | |||
"message": "Description changed", | |||
"email_alert_recipients": [ | |||
{ "email_by_document_field": "owner" } | |||
] | |||
} | |||
] |
@@ -2,7 +2,7 @@ from frappe.__version__ import __version__ | |||
app_name = "frappe" | |||
app_title = "Frappe Framework" | |||
app_publisher = "Web Notes Technologies Pvt. Ltd. and Contributors" | |||
app_publisher = "Web Notes Technologies Pvt. Ltd." | |||
app_description = "Full Stack Web Application Framwork in Python" | |||
app_icon = "assets/frappe/images/frappe.svg" | |||
app_version = __version__ | |||
@@ -51,8 +51,17 @@ has_permission = { | |||
doc_events = { | |||
"*": { | |||
"on_update": "frappe.core.doctype.notification_count.notification_count.clear_doctype_notifications", | |||
"on_cancel": "frappe.core.doctype.notification_count.notification_count.clear_doctype_notifications", | |||
"after_insert": "frappe.core.doctype.email_alert.email_alert.trigger_email_alerts", | |||
"validate": "frappe.core.doctype.email_alert.email_alert.trigger_email_alerts", | |||
"on_update": [ | |||
"frappe.core.doctype.notification_count.notification_count.clear_doctype_notifications", | |||
"frappe.core.doctype.email_alert.email_alert.trigger_email_alerts" | |||
], | |||
"on_submit": "frappe.core.doctype.email_alert.email_alert.trigger_email_alerts", | |||
"on_cancel": [ | |||
"frappe.core.doctype.notification_count.notification_count.clear_doctype_notifications", | |||
"frappe.core.doctype.email_alert.email_alert.trigger_email_alerts" | |||
], | |||
"on_trash": "frappe.core.doctype.notification_count.notification_count.clear_doctype_notifications" | |||
}, | |||
"User Vote": { | |||
@@ -70,6 +79,7 @@ scheduler_events = { | |||
"frappe.core.doctype.notification_count.notification_count.delete_event_notification_count", | |||
"frappe.core.doctype.event.event.send_event_digest", | |||
"frappe.sessions.clear_expired_sessions", | |||
"frappe.core.doctype.email_alert.email_alert.trigger_daily_alerts", | |||
], | |||
"hourly": [ | |||
"frappe.website.doctype.website_group.website_group.clear_event_cache" | |||
@@ -83,6 +83,10 @@ class BaseDocument(object): | |||
else: | |||
self.__dict__[key] = value | |||
def delete(self, key): | |||
if key in self.__dict__: | |||
del self.__dict__[key] | |||
def append(self, key, value=None): | |||
if value==None: | |||
value={} | |||
@@ -124,8 +124,11 @@ class Document(BaseDocument): | |||
self.set_new_name() | |||
self.run_method("before_insert") | |||
self.set_parent_in_children() | |||
self.set("__in_insert", True) | |||
self.run_before_save_methods() | |||
self._validate() | |||
self.delete("__in_insert") | |||
# run validate, on update etc. | |||
@@ -140,7 +143,9 @@ class Document(BaseDocument): | |||
d.db_insert() | |||
self.run_method("after_insert") | |||
self.set("__in_insert", True) | |||
self.run_post_save_methods() | |||
self.delete("__in_insert") | |||
return self | |||
@@ -51,7 +51,13 @@ frappe.Application = Class.extend({ | |||
// control panel startup code | |||
this.run_startup_js(); | |||
if(frappe.boot) { | |||
if(localStorage.getItem("session_lost_route")) { | |||
window.location.hash = localStorage.getItem("session_lost_route"); | |||
localStorage.removeItem("session_lost_route"); | |||
} | |||
// route to home page | |||
frappe.route(); | |||
} | |||
@@ -176,6 +176,7 @@ frappe.request.cleanup = function(opts, r) { | |||
// session expired? - Guest has no business here! | |||
if(r.session_expired || frappe.get_cookie("sid")==="Guest") { | |||
if(!frappe.app.logged_out) { | |||
localStorage.setItem("session_lost_route", location.hash); | |||
msgprint(__('Session Expired. Logging you out')); | |||
frappe.app.logout(); | |||
} | |||
@@ -10,7 +10,7 @@ from frappe.modules import load_doctype_module, get_module_name | |||
from frappe.utils import cstr | |||
def main(app=None, module=None, doctype=None, verbose=False, tests=()): | |||
def main(app=None, module=None, doctype=None, verbose=False, tests=(), force=False): | |||
frappe.flags.print_messages = verbose | |||
frappe.flags.in_test = True | |||
@@ -29,7 +29,7 @@ def main(app=None, module=None, doctype=None, verbose=False, tests=()): | |||
frappe.get_attr(fn)() | |||
if doctype: | |||
ret = run_tests_for_doctype(doctype, verbose=verbose, tests=tests) | |||
ret = run_tests_for_doctype(doctype, verbose=verbose, tests=tests, force=force) | |||
elif module: | |||
ret = run_tests_for_module(module, verbose=verbose, tests=tests) | |||
else: | |||
@@ -63,10 +63,13 @@ def run_all_tests(app=None, verbose=False): | |||
return unittest.TextTestRunner(verbosity=1+(verbose and 1 or 0)).run(test_suite) | |||
def run_tests_for_doctype(doctype, verbose=False, tests=()): | |||
def run_tests_for_doctype(doctype, verbose=False, tests=(), force=False): | |||
module = frappe.db.get_value("DocType", doctype, "module") | |||
test_module = get_module_name(doctype, module, "test_") | |||
make_test_records(doctype, verbose=verbose) | |||
if force: | |||
for name in frappe.db.sql_list("select name from `tab%s`" % doctype): | |||
frappe.delete_doc(doctype, name, force=True) | |||
make_test_records(doctype, verbose=verbose, force=force) | |||
module = frappe.get_module(test_module) | |||
return _run_unittest(module, verbose=verbose, tests=tests) | |||
@@ -107,7 +110,7 @@ def _add_test(path, filename, verbose, test_suite=None): | |||
module = imp.load_source(filename[:-3], os.path.join(path, filename)) | |||
test_suite.addTest(unittest.TestLoader().loadTestsFromModule(module)) | |||
def make_test_records(doctype, verbose=0): | |||
def make_test_records(doctype, verbose=0, force=False): | |||
frappe.flags.mute_emails = True | |||
if not frappe.db: | |||
@@ -119,8 +122,8 @@ def make_test_records(doctype, verbose=0): | |||
if options not in frappe.local.test_objects: | |||
frappe.local.test_objects[options] = [] | |||
make_test_records(options, verbose) | |||
make_test_records_for_doctype(options, verbose) | |||
make_test_records(options, verbose, force) | |||
make_test_records_for_doctype(options, verbose, force) | |||
def get_modules(doctype): | |||
module = frappe.db.get_value("DocType", doctype, "module") | |||
@@ -155,7 +158,7 @@ def get_dependencies(doctype): | |||
return options_list | |||
def make_test_records_for_doctype(doctype, verbose=0): | |||
def make_test_records_for_doctype(doctype, verbose=0, force=False): | |||
module, test_module = get_modules(doctype) | |||
if verbose: | |||
@@ -14,8 +14,8 @@ from frappe.utils import cint, get_url, nowdate | |||
class BulkLimitCrossedError(frappe.ValidationError): pass | |||
def send(recipients=None, sender=None, doctype='User', email_field='email', | |||
subject='[No Subject]', message='[No Content]', ref_doctype=None, ref_docname=None, | |||
add_unsubscribe_link=True): | |||
subject='[No Subject]', message='[No Content]', ref_doctype=None, | |||
ref_docname=None, add_unsubscribe_link=True): | |||
def is_unsubscribed(rdata): | |||
if not rdata: | |||
@@ -12,7 +12,7 @@ from __future__ import unicode_literals | |||
import frappe | |||
import frappe.utils | |||
from frappe.utils.file_lock import create_lock, check_lock, delete_lock, LockTimeoutError | |||
from frappe.utils.file_lock import create_lock, check_lock, delete_lock | |||
from datetime import datetime | |||
DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S' | |||
@@ -95,7 +95,7 @@ def log(method, message=None): | |||
d = frappe.new_doc("Scheduler Log") | |||
d.method = method | |||
d.error = message | |||
d.insert() | |||
d.insert(ignore_permissions=True) | |||
frappe.db.commit() | |||