@@ -1128,13 +1128,13 @@ def get_test_records(doctype): | |||
else: | |||
return [] | |||
def format_value(value, df, doc=None, currency=None): | |||
def format_value(*args, **kwargs): | |||
"""Format value with given field properties. | |||
:param value: Value to be formatted. | |||
:param df: DocField object with properties `fieldtype`, `options` etc.""" | |||
:param df: (Optional) DocField object with properties `fieldtype`, `options` etc.""" | |||
import frappe.utils.formatters | |||
return frappe.utils.formatters.format_value(value, df, doc, currency=currency) | |||
return frappe.utils.formatters.format_value(*args, **kwargs) | |||
def get_print(doctype=None, name=None, print_format=None, style=None, html=None, as_pdf=False, doc=None): | |||
"""Get Print Format for given document. | |||
@@ -83,6 +83,7 @@ class Report(Document): | |||
return out | |||
@Document.whitelist | |||
def toggle_disable(self, disable): | |||
self.db_set("disabled", cint(disable)) |
@@ -20,6 +20,26 @@ frappe.ui.form.on('Auto Email Report', { | |||
frm.trigger('show_filters'); | |||
} | |||
} | |||
if(!frm.is_new()) { | |||
frm.add_custom_button(__('Download'), function() { | |||
var w = window.open( | |||
frappe.urllib.get_full_url( | |||
"/api/method/frappe.email.doctype.auto_email_report.auto_email_report.download?" | |||
+"name="+encodeURIComponent(frm.doc.name))); | |||
if(!w) { | |||
msgprint(__("Please enable pop-ups")); return; | |||
} | |||
}); | |||
frm.add_custom_button(__('Send Now'), function() { | |||
frappe.call({ | |||
method: 'frappe.email.doctype.auto_email_report.auto_email_report.send_now', | |||
args: {name: frm.doc.name}, | |||
callback: function() { | |||
msgprint(__('Scheduled to send')); | |||
} | |||
}); | |||
}); | |||
} | |||
}, | |||
show_filters: function(frm) { | |||
var wrapper = $(frm.get_field('filters_display').wrapper); | |||
@@ -294,7 +294,7 @@ | |||
"label": "Format", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "HTML\nXLS\nCSV", | |||
"options": "XLS\nHTML\nCSV", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
@@ -369,7 +369,7 @@ | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-09-01 05:36:00.898683", | |||
"modified": "2016-09-14 02:00:21.618956", | |||
"modified_by": "Administrator", | |||
"module": "Email", | |||
"name": "Auto Email Report", | |||
@@ -7,6 +7,8 @@ import frappe | |||
from frappe import _ | |||
from frappe.model.document import Document | |||
import frappe.utils | |||
from frappe.utils.xlsutils import get_xls | |||
from frappe.utils.csvutils import to_csv | |||
max_reports_per_user = 3 | |||
@@ -20,16 +22,16 @@ class AutoEmailReport(Document): | |||
def validate_emails(self): | |||
'''Cleanup list of emails''' | |||
if ',' in self.emails: | |||
self.emails.replace(',', '\n') | |||
if ',' in self.email_to: | |||
self.email_to.replace(',', '\n') | |||
valid = [] | |||
for email in self.emails.split(): | |||
for email in self.email_to.split(): | |||
if email: | |||
frappe.utils.validate_email_add(email, True) | |||
valid.append(email) | |||
self.emails = '\n'.join(valid) | |||
self.email_to = '\n'.join(valid) | |||
def validate_report_count(self): | |||
'''check that there are only 3 enabled reports per user''' | |||
@@ -37,48 +39,85 @@ class AutoEmailReport(Document): | |||
if count > max_reports_per_user: | |||
frappe.throw(_('Only {0} emailed reports are allowed per user').format(max_reports_per_user)) | |||
def send(self): | |||
def get_report_content(self): | |||
'''Returns file in for the report in given format''' | |||
report = frappe.get_doc('Report', self.report) | |||
data = report.get_data(limit=500, user = self.user, filters = self.filters) | |||
raw = report.get_data(limit=500, user = self.user, filters = self.filters) | |||
if self.format == 'HTML': | |||
return self.get_html_table(raw) | |||
elif self.format == 'XLS': | |||
return get_xls(raw) | |||
elif self.format == 'CSV': | |||
return to_csv(raw) | |||
else: | |||
frappe.throw(_('Invalid Output Format')) | |||
def get_html_table(self, data): | |||
return frappe.render_template('frappe/templates/includes/print_table.html', { | |||
'headings': data[0], | |||
'data': data[1:] | |||
}) | |||
def get_file_name(self): | |||
return "{0}.{1}".format(self.report.replace(" ", "-").replace("/", "-"), self.format.lower()) | |||
def send(self): | |||
data = self.get_report_content() | |||
message = '<p>{0}</p>'.format(_('{0} generated on {1}').format(self.name, | |||
frappe.utils.format_datetime(frappe.utils.now_datetime()))) | |||
attachments = None | |||
if self.report_format == 'HTML': | |||
message += self.get_html_table(data) | |||
if self.report_format == 'XLS': | |||
attachments.append(self.get_xls()) | |||
if self.format=='HTML': | |||
message += '<hr>' + data | |||
else: | |||
attachments = [{ | |||
'fname': self.get_file_name(), | |||
'fcontent': data | |||
}] | |||
frappe.sendmail( | |||
recipients = self.emails.split(), | |||
recipients = self.email_to.split(), | |||
subject = self.name, | |||
message = message, | |||
attachments = attachments | |||
) | |||
def get_html_table(self, data): | |||
return '' | |||
@frappe.whitelist() | |||
def download(name): | |||
'''Download report locally''' | |||
auto_email_report = frappe.get_doc('Auto Email Report', name) | |||
auto_email_report.check_permission() | |||
data = auto_email_report.get_report_content() | |||
def get_csv(self, data): | |||
return | |||
frappe.local.response.filecontent = data | |||
frappe.local.response.type = "download" | |||
frappe.local.response.filename = auto_email_report.get_file_name() | |||
def get_xls(self, data): | |||
return | |||
@frappe.whitelist() | |||
def send_now(name): | |||
'''Send Auto Email report now''' | |||
auto_email_report = frappe.get_doc('Auto Email Report', name) | |||
auto_email_report.check_permission() | |||
auto_email_report.send() | |||
def send_daily(): | |||
'''Check reports to be sent daily''' | |||
now = frappe.utils.now_datetime() | |||
for report in frappe.get_all('Auto Email Report', {'enabled': 1, 'frequency': ('in', ('Daily', 'Weekly'))}): | |||
for report in frappe.get_all('Auto Email Report', | |||
{'enabled': 1, 'frequency': ('in', ('Daily', 'Weekly'))}): | |||
auto_email_report = frappe.get_doc('Auto Email Report', report.name) | |||
# if not correct weekday, skip | |||
if auto_email_report.frequency=='Weekly': | |||
# if not correct weekday, skip | |||
if now.weekday()!={'Monday':0,'Tuesday':1,'Wednesday':2, | |||
'Thursday':3,'Friday':4,'Saturday':5,'Sunday':6}[auto_email_report.weekday]: | |||
continue | |||
auto_email_report.send() | |||
auto_email_report.send() | |||
def send_monthly(): | |||
'''Check reports to be sent monthly''' | |||
@@ -136,7 +136,7 @@ class Document(BaseDocument): | |||
self.latest = frappe.get_doc(self.doctype, self.name) | |||
return self.latest | |||
def check_permission(self, permtype, permlabel=None): | |||
def check_permission(self, permtype='read', permlabel=None): | |||
"""Raise `frappe.PermissionError` if not permitted""" | |||
if not self.has_permission(permtype): | |||
self.raise_no_permission_to(permlabel or permtype) | |||
@@ -6,18 +6,18 @@ | |||
<meta name="viewport" content="width=device-width, initial-scale=1"> | |||
<meta name="description" content=""> | |||
<meta name="author" content=""> | |||
<title>{%= title %}</title> | |||
<link href="{%= frappe.urllib.get_base_url() %}/assets/frappe/css/bootstrap.css" rel="stylesheet"> | |||
<title>{{ title }}</title> | |||
<link href="{{ base_url }}/assets/frappe/css/bootstrap.css" rel="stylesheet"> | |||
<link type="text/css" rel="stylesheet" | |||
href="{%= frappe.urllib.get_base_url() %}/assets/frappe/css/font-awesome.css"> | |||
href="{{ base_url }}/assets/frappe/css/font-awesome.css"> | |||
<style> | |||
{%= frappe.boot.print_css %} | |||
{{ print_css }} | |||
</style> | |||
</head> | |||
<body> | |||
<div class="print-format-gutter"> | |||
<div class="print-format"> | |||
{%= content %} | |||
{{ content }} | |||
</div> | |||
</div> | |||
</body> | |||
@@ -1,41 +1,37 @@ | |||
<!-- title --> | |||
{% if(title) { %} | |||
<h2>{%= __(title) %}</h2> | |||
{% if title %} | |||
<h2>{{ __(title) }}</h2> | |||
<hr> | |||
{% } %} | |||
{{ endif }} | |||
<table class="table table-bordered"> | |||
<!-- heading --> | |||
<thead> | |||
<tr> | |||
{% var columns_length = columns.length; | |||
for (var i=0; i < columns_length; i++) { | |||
var col = columns[i]; %} | |||
{% if(col.name && col._id !== "_check") { %} | |||
<th style="min-width: {%= col.minWidth %}px" | |||
{% if(col.docfield && in_list(["Float", "Currency", "Int"], | |||
col.docfield.fieldtype)) { %} | |||
{% for col in columns %} | |||
{% if col.name && col._id !== "_check" %} | |||
<th style="min-width: {{ col.minWidth }}px" | |||
{% if col.docfield && in_list(["Float", "Currency", "Int"], col.docfield.fieldtype) %} | |||
class="text-right" | |||
{% } %}>{%= __(col.name) %}</th> | |||
{% } %} | |||
{% } %} | |||
{% endif %}>{{ __(col.name) }}</th> | |||
{% endif %} | |||
{% endfor %} | |||
</tr> | |||
</thead> | |||
<!-- body --> | |||
<tbody> | |||
{% for (var i=0, l= data.length; i < l; i++) { | |||
var row = data[i]; %} | |||
{% for row in data %} | |||
<tr> | |||
{% for(var c=0; c < columns_length; c++) { var col = columns[c];%} | |||
{% if(col.name && col._id !== "_check") { %} | |||
{% for col in columns %} | |||
{% if col.name && col._id !== "_check" %} | |||
{% var value = col.fieldname ? row[col.fieldname] : row[col.id]; %} | |||
<td>{%= col.formatter | |||
<td>{{ col.formatter | |||
? col.formatter(i, c, value, col, row, true) | |||
: value %}</td> | |||
{% } %} | |||
{% } %} | |||
: value }}</td> | |||
{% endif %} | |||
{% endfor %} | |||
</tr> | |||
{% } %} | |||
{% endfor %} | |||
</tbody> | |||
</table> |
@@ -96,6 +96,8 @@ frappe.render_grid = function(opts) { | |||
} | |||
// render HTML wrapper page | |||
opts.base_url = frappe.urllib.get_base_url(); | |||
opts.print_cess = frappe.boot.print_css; | |||
var html = frappe.render_template("print_template", opts); | |||
var w = window.open(); | |||
@@ -0,0 +1,22 @@ | |||
<table cellpadding=2px cellspacing=0 border=1px style='width:100%; border-collapse:collapse;'> | |||
<thead> | |||
<tr> | |||
{% for col in headings %} | |||
<th> | |||
{{ col }} | |||
</th> | |||
{% endfor %} | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{% for row in data %} | |||
<tr> | |||
{% for val in row %} | |||
<td> | |||
{{ frappe.format(val) }} | |||
</td> | |||
{% endfor %} | |||
</td> | |||
{% endfor %} | |||
</tbody> | |||
</table> |
@@ -3,13 +3,29 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
import datetime | |||
from frappe.utils import formatdate, fmt_money, flt, cstr, cint, format_datetime | |||
from frappe.model.meta import get_field_currency, get_field_precision | |||
import re | |||
def format_value(value, df, doc=None, currency=None, translated=False): | |||
# Convert dict to object if necessary | |||
if (isinstance(df, dict)): | |||
def format_value(value, df=None, doc=None, currency=None, translated=False): | |||
'''Format value based on given fieldtype, document reference, currency reference. | |||
If docfield info (df) is not given, it will try and guess based on the datatype of the value''' | |||
if not df: | |||
df = frappe._dict() | |||
if isinstance(value, datetime.datetime): | |||
df.fieldtype = 'Datetime' | |||
elif isinstance(value, datetime.date): | |||
df.fieldtype = 'Date' | |||
elif isinstance(value, int): | |||
df.fieldtype = 'Int' | |||
elif isinstance(value, float): | |||
df.fieldtype = 'Float' | |||
else: | |||
df.fieldtype = 'Data' | |||
elif (isinstance(df, dict)): | |||
# Convert dict to object if necessary | |||
df = frappe._dict(df) | |||
if value is None: | |||
@@ -78,6 +78,7 @@ def get_allowed_functions_for_jenv(): | |||
"frappe": { | |||
"_": frappe._, | |||
"get_url": frappe.utils.get_url, | |||
'format': frappe.format_value, | |||
"format_value": frappe.format_value, | |||
"format_date": frappe.utils.data.global_date_format, | |||
"form_dict": getattr(frappe.local, 'form_dict', {}), | |||
@@ -0,0 +1,32 @@ | |||
from __future__ import unicode_literals | |||
import frappe, xlwt, StringIO, datetime | |||
from frappe import _ | |||
def get_xls(data): | |||
'''Convert data to xls''' | |||
stream = StringIO.StringIO() | |||
workbook = xlwt.Workbook() | |||
sheet = workbook.add_sheet(_("Sheet 1")) | |||
# formats | |||
dateformat = xlwt.easyxf(num_format_str= | |||
(frappe.defaults.get_global_default("date_format") or "yyyy-mm-dd")) | |||
bold = xlwt.easyxf('font: bold 1') | |||
for i, row in enumerate(data): | |||
for j, val in enumerate(row): | |||
f = None | |||
if isinstance(val, (datetime.datetime, datetime.date)): | |||
f = dateformat | |||
if i==0: | |||
f = bold | |||
if f: | |||
sheet.write(i, j, val, f) | |||
else: | |||
sheet.write(i, j, val) | |||
workbook.save(stream) | |||
stream.seek(0) | |||
return stream.read() |