Skip to content

Commit

Permalink
Merge pull request #54 from nycrecords/health-screen
Browse files Browse the repository at this point in the history
  • Loading branch information
joelbcastillo authored Jun 25, 2020
2 parents 85a6edc + 302f4cd commit 8571cda
Show file tree
Hide file tree
Showing 14 changed files with 706 additions and 205 deletions.
2 changes: 2 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ psycopg2-binary = "*"
sphinx = "*"
sphinx-rtd-theme = "*"
python-dotenv = "*"
email-validator = "*"
faker = "*"

[requires]
python_version = "3.6"
Expand Down
492 changes: 293 additions & 199 deletions Pipfile.lock

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions app/email_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,17 @@ def send_email(to, subject, template, **kwargs):
thr = Thread(target=send_async_email, args=[app, msg])
thr.start()
return thr


def send_health_screen_confirmation_email(to, bcc, subject, filename, attachment, name):
app = current_app._get_current_object()
msg = Message(subject, sender="healthcheck@records.nyc.gov", recipients=to, bcc=bcc)

msg.html = render_template(
"main/email/employee_health_screen_results.html", name=name
)

msg.attach(filename, "application/pdf", attachment)
thr = Thread(target=send_async_email, args=[app, msg])
thr.start()
return thr
22 changes: 22 additions & 0 deletions app/main/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,25 @@ class GenerateMultipleTimesheetsForm(Form):

class ExportForm(Form):
export = SubmitField("Export")


class HealthScreenForm(Form):
name = StringField("Name", validators=[DataRequired()])
email = StringField(
"Email",
validators=[
DataRequired(),
Email("You must provide a valid @records.nyc.gov email address."),
],
)
date = StringField(
"Date",
default=datetime.today().strftime("%-m/%-d/%Y"),
validators=[DataRequired()],
)
division = SelectField("Division", choices=divisions, validators=[DataRequired()])
questionnaire_confirmation = BooleanField(validators=[DataRequired()])
report_to_work = SelectField(
choices=[("", ""), ("Yes", "Yes"), ("No", "No")], validators=[DataRequired()]
)
submit = SubmitField("Submit")
33 changes: 32 additions & 1 deletion app/main/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@
generate_timetable,
generate_signature_template,
generate_footer,
generate_health_screen_confirmation,
)
from .. import db
from ..email_notification import send_email
from ..email_notification import send_email, send_health_screen_confirmation_email
from ..models import User, Event, Tag, Vacation
from io import BytesIO
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from pytz import timezone


Expand Down Expand Up @@ -552,3 +556,30 @@ def create_csv(events=None):
output.headers["Content-Disposition"] = "attachment; filename=export.csv"
output.headers["Content-type"] = "text/csv"
return output


def process_health_screen_confirmation(
name, email, division, date, questionnaire_confirmation, report_to_work
):

buffer = BytesIO()
c = canvas.Canvas(buffer, pagesize=letter)
generate_health_screen_confirmation(
c, name, division, date, questionnaire_confirmation, report_to_work
)
c.save()
pdf = buffer.getvalue()
buffer.close()

filename = "{username}-health-check-{date}.pdf".format(
username=email.split("@")[0],
date=datetime.strptime(date, "%m/%d/%Y").strftime("%Y-%m-%d"),
)
send_health_screen_confirmation_email(
["healthcheck@records.nyc.gov"],
[email],
"Health Screening Confirmation - " + name,
filename,
pdf,
name,
)
39 changes: 39 additions & 0 deletions app/main/pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,3 +257,42 @@ def generate_footer(canvas_field):
canvas_field.drawString(470, 20, datetime.now().strftime("%b %d, %Y %l:%M:%S %p"))
canvas_field.line(25, 30, width - 25, 30)
current_app.logger.info("PDF: Finished generating footer...")


def generate_health_screen_confirmation(
canvas_field, name, division, date, questionnaire_confirmation, report_to_work
):
canvas_field.setFont("Times-Bold", 14)
canvas_field.drawString(220, length - 52, "Employee Health Screening")

canvas_field.setFont("Times-Roman", 12)
canvas_field.drawString(70, length - 110, "Name: " + name)

canvas_field.drawString(70, length - 140, "Division: " + division)

canvas_field.drawString(70, length - 170, "Date: " + date)

if questionnaire_confirmation:
canvas_field.drawString(
70,
length - 200,
"1. Employee confirms they have completed the entire health check questionnaire: Yes",
)
else:
canvas_field.drawString(
70,
length - 200,
"1. Employee confirms they have completed the entire health check questionnaire: No",
)
canvas_field.drawString(
70,
length - 230,
"2. Based on the questionnaire results, the employee may return to work on {date}: {report_to_work}".format(
date=date, report_to_work=report_to_work
),
)
canvas_field.drawString(
70,
length - 300,
"If your response is “no”, please contact the Administration Division at healthcheck@records.nyc.gov.",
)
33 changes: 33 additions & 0 deletions app/main/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
RequestVacationForm,
FilterVacationForm,
ExportForm,
HealthScreenForm,
)
from .modules import (
process_clock,
Expand All @@ -50,6 +51,7 @@
generate_timesheet,
generate_timesheets,
create_csv,
process_health_screen_confirmation,
)
from .payments import get_payrate_before_or_after, calculate_hours_worked
from .requests import (
Expand Down Expand Up @@ -915,3 +917,34 @@ def review_vacations():
clear=clear_form,
query_has_results=query_has_results,
)


@main.route("/healthscreen", methods=["GET", "POST"])
def health_screen_confirm():
form = HealthScreenForm()

if form.validate_on_submit():
if (
not request.form.get("email", "").split("@")[-1].lower()
== current_app.config["EMAIL_DOMAIN"]
):
form.email.errors.append("You must enter a @records.nyc.gov email address.")
return render_template("main/health_screen_confirm.html", form=form)
name = request.form["name"]
email = request.form["email"].lower()
date = request.form["date"]
division = request.form["division"]
questionnaire_confirmation = request.form["division"]
report_to_work = request.form["report_to_work"]

# Generate and email PDF
process_health_screen_confirmation(
name, email, division, date, questionnaire_confirmation, report_to_work
)

flash(
"Screening completed. You will receive a confirmation email shortly.",
category="success",
)
return redirect(url_for("main.health_screen_confirm"))
return render_template("main/health_screen_confirm.html", form=form)
1 change: 1 addition & 0 deletions app/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="{{ url_for('main.health_screen_confirm') }}" style="color:white">Employee Health Screening</a></li>
<li>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button"
Expand Down
162 changes: 162 additions & 0 deletions app/templates/base_healthscreen.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
{% extends "bootstrap/base.html" %}

{% block title %}TimeClock{% endblock %}
<!-- title block inherited from bootstrap/base.html -->

{% block head %}
{{ super() }}
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.0/themes/base/jquery-ui.css">
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"
media="screen">
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.0/themes/base/jquery-ui.css">
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-timepicker/1.10.0/jquery.timepicker.css" rel="stylesheet"
media="screen">
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-timepicker/1.10.0/jquery.timepicker.min.css" rel="stylesheet"
media="screen">
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-timepicker/1.10.0/jquery.timepicker.min.css.map"
rel="stylesheet" media="screen">
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-timepicker/1.10.0/jquery.timepicker.js">
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-timepicker/1.10.0/jquery.timepicker.min.js">
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='styles/main.css') }}" />
{% endblock %}

{% block navbar %}
<!-- Navigation base HTML will go here -->
<div class="navbar navbar-default" role="navigation" style="border-radius: 0; font-family: 'Sofia Pro Soft', 'Trebuchet MS'; -webkit-font-smoothing: antialiased;
background-color: #2a6496; border-color: #2a6496;">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="{{ url_for('main.health_screen_confirm') }}" style="color:white">Employee
Health Screen</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="history-dropdown"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" style="margin-top:9px; color:white; background-color:#2a6496;
border: 0">
Telework Instructions
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="history-dropdown">
<li><a href="https://records-timeclock.readthedocs.io/en/latest/" target="_blank">TimeClock
Help</a></li>
</li>
<li>
<a href="{{ url_for('static', filename="files/DORIS Remote Access Instructions.pdf") }}"
target="_blank">Remote Access Instructions</a></li>
</li>
{% if current_user.is_authenticated %}
<li>
<a href="{{ url_for('static', filename="files/DORIS VM Quick Reference.pdf") }}"
target="_blank">Voicemail Quick Reference Guide</a></li>
</li>
<li>
<a href="{{ url_for('static', filename="files/DORIS - Guidelines for Teleworking Employees.pdf") }}"
target="_blank">Guidelines for Teleworking </a></li>
</li>
{% endif %}
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
{% endblock %}

{% block content %}
<div class="container" style="font-family: 'Sofia Pro Soft'; -webkit-font-smoothing: antialiased">
{% for category, message in get_flashed_messages(with_categories=True) %}
{% if category == 'error' %}
<div class="alert alert-danger">
{% else %}
<div class="alert alert-{{ category }}">
{% endif %}
<button type="button" class="close" data-dismiss="alert">&times;</button>
{{ message }}
</div>
{% endfor %}

{% block page_content %}
{% endblock %}
</div>
{% endblock %}



{% block scripts %}
<!-- Include any JS scripts here -->
{{ super() }}
{{ moment.include_moment() }}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/jquery-timepicker/1.10.0/jquery.timepicker.js"></script>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/jquery-timepicker/1.10.0/jquery.timepicker.min.js"></script>
<!-- <script>
$(document).ready(function () {
var questionOne = $('#questionOne');
var questionOneItem = $('#questionOneItem');
var questionTwo = $('#questionTwo');
var questionTwoItem = $('#questionTwoItem');
var questionThree = $('#questionThree');
var questionThreeItem = $('#questionThreeItem');
var questionFour = $('#questionFour');
var questionFourItem = $('#questionFourItem');
var resultsSpan = $('#results');
questionOne.change(function () {
var selectedValue = $(this).children("option:selected").val();
if (selectedValue === "yes") {
questionTwoItem.hide();
questionThreeItem.hide();
questionFourItem.hide();
resultsSpan.html("No further screening is needed. The employee may not report to work. Please submit the health screen confirmation below and contact the Administration Division by emailing <a href=\"mailto:healthcheck@records.nyc.gov\">healthcheck@records.nyc.gov</a>");
} else {
questionTwoItem.show();
questionThreeItem.show();
questionFourItem.show();
resultsSpan.html("");
}
})
questionTwo.change(function () {
var selectedValue = $(this).children("option:selected").val();
if (selectedValue === "yes") {
questionThreeItem.hide();
questionFourItem.hide();
resultsSpan.html("No further screening is needed. The employee may not report to work. Please submit the health screen confirmation below and contact the Administration Division by emailing <a href=\"mailto:healthcheck@records.nyc.gov\">healthcheck@records.nyc.gov</a>");
} else {
questionThreeItem.show();
questionFourItem.show();
resultsSpan.html("");
}
})
questionThree.change(function () {
var selectedValue = $(this).children("option:selected").val();
if (selectedValue === "yes") {
questionFourItem.hide();
resultsSpan.html("No further screening is needed. The employee may not report to work. Please submit the health screen confirmation below and contact the Administration Division by emailing <a href=\"mailto:healthcheck@records.nyc.gov\">healthcheck@records.nyc.gov</a>");
} else {
questionFourItem.show();
resultsSpan.html("");
}
})
questionFour.change(function () {
var selectedValue = $(this).children("option:selected").val();
if (selectedValue === "yes") {
resultsSpan.html("No further screening is needed. The employee may not report to work. Please submit the health screen confirmation below and contact the Administration Division by emailing <a href=\"mailto:healthcheck@records.nyc.gov\">healthcheck@records.nyc.gov</a>");
} else {
resultsSpan.html("The employee may report to work.");
}
})
});
</script> -->
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>Employee Health Screen results for {{ name }} attached.</p>
Loading

0 comments on commit 8571cda

Please sign in to comment.