From fd39ca7df7f214175c670c0bc76d6d6cf464b380 Mon Sep 17 00:00:00 2001 From: kououken Date: Sat, 2 Mar 2019 14:10:00 -0800 Subject: [PATCH 01/18] Implemented tests for all policy rules. --- back/backend/policy.py | 25 +++++++----- back/backend/test.py | 3 -- back/backend/test_policy.py | 81 +++++++++++++++++++++++++++++++++++++ back/backend/tests.py | 3 -- 4 files changed, 95 insertions(+), 17 deletions(-) delete mode 100644 back/backend/test.py create mode 100644 back/backend/test_policy.py delete mode 100644 back/backend/tests.py diff --git a/back/backend/policy.py b/back/backend/policy.py index 41f8b73..04fb721 100644 --- a/back/backend/policy.py +++ b/back/backend/policy.py @@ -1,8 +1,11 @@ -from datetime import date +import datetime #### Classes for policy, sections. Do not edit these. ##################################################### +def to_date(iso8601): + return datetime.datetime.strptime(iso8601, "%Y-%m-%d") + class Policy(): """ Represents the policy for the company/organization. @@ -127,17 +130,17 @@ def lowest_fare_rule(report, fields): maximum = lowest_fare + 350 else: maximum = lowest_fare + 600 - if fields['preferred_fare'] > maximum: + if fields['preferred_flight_fare'] > maximum: return "For the lowest fare you have provided, your maximum in-policy fare amount is {} USD.".format(maximum) return None planning_section.add_rule(title="Lowest fare check", rule=lowest_fare_rule) def departure_date_limit_rule(report, fields): - days_to_departure = date(fields['departure_date']) - date(fields['screenshot_date']) - if days_to_departure < 14: + days_to_departure = to_date(fields['departure_date']) - to_date(fields['screenshot_date']) + if days_to_departure < datetime.timedelta(days=14): return "Flights must be booked at least 14 days in advance." - if days_to_departure > 365: + if days_to_departure > datetime.timedelta(days=365): return "Flights must be booked no more than 365 days in advance." return None @@ -173,9 +176,9 @@ def actual_fare_limit_rule(report, fields): flight_section.add_rule(title="Fare limits", rule=actual_fare_limit_rule) def request_date_rule(report, fields): - now = date.today() - last_travel = date(fields['return_date']) - if now - last_travel > 90: + now = datetime.datetime.now() + last_travel = to_date(fields['return_date']) + if now - last_travel > datetime.timedelta(days=90): return "Reimbursement requests must be made within 90 days of the last day of travel." return None @@ -198,9 +201,9 @@ lodging_section = Section( ) def nightly_rate_check(report, fields): - checkin_date = date(fields['check_in_date']) - checkout_date = date(fields['check_out_date']) - duration = checkout_date - checkin_date + check_in_date = to_date(fields['check_in_date']) + check_out_date = to_date(fields['check_out_date']) + duration = (check_out_date - check_in_date).days if fields['cost'] > duration * fields['per_diem_rate']: return "The average nightly rate cannot exceed the U.S. GSA rate." return None diff --git a/back/backend/test.py b/back/backend/test.py deleted file mode 100644 index 6ecdccb..0000000 --- a/back/backend/test.py +++ /dev/null @@ -1,3 +0,0 @@ -from policy import pol - -print(pol) diff --git a/back/backend/test_policy.py b/back/backend/test_policy.py new file mode 100644 index 0000000..f0f4ad6 --- /dev/null +++ b/back/backend/test_policy.py @@ -0,0 +1,81 @@ +from django.test import TestCase +from .policy import pol +from unittest import mock + +class PolicyTests(TestCase): + report = {"key":"value"} + + def test_general_section_pre_post_trip_check(self): + fields = {'after_trip':True} + result = pol.sections[0].rules[0]['rule'](self.report, fields) + self.assertEqual(result, "If you have already take the trip your request will require special approval by the administrator. You may skip the following 'Pre-trip Planning' section.") + + def test_pre_flight_section_fare_limit_domestic(self): + fields = {'preferred_flight_fare':751,'international_flight':False} + result = pol.sections[1].rules[0]['rule'](self.report, fields) + self.assertEqual(result, "Fares for domestic flights over 750 USD require Conservancy pre-approval, even if other policy conditions have been met.") + + def test_pre_flight_section_fare_limit_international(self): + fields = {'preferred_flight_fare':1651,'international_flight':True} + result = pol.sections[1].rules[0]['rule'](self.report, fields) + self.assertEqual(result, "Fares for international flights over 1,650 USD require Conservancy pre-approval, even if other policy conditions have been met.") + + def test_pre_flight_section_lowest_fare_check_less_than_zero(self): + fields = {'lowest_fare_duration':10,'preferred_flight_duration':11,'lowest_fare':100,'preferred_flight_fare':1000} + result = pol.sections[1].rules[1]['rule'](self.report, fields) + self.assertEqual(result, "For the lowest fare you have provided, your maximum in-policy fare amount is 200 USD.") + + def test_pre_flight_section_lowest_fare_check_less_than_three(self): + fields = {'lowest_fare_duration':10,'preferred_flight_duration':8,'lowest_fare':100,'preferred_flight_fare':1000} + result = pol.sections[1].rules[1]['rule'](self.report, fields) + self.assertEqual(result, "For the lowest fare you have provided, your maximum in-policy fare amount is 200 USD.") + + def test_pre_flight_section_lowest_fare_check_less_than_six(self): + fields = {'lowest_fare_duration':10,'preferred_flight_duration':5,'lowest_fare':100,'preferred_flight_fare':1000} + result = pol.sections[1].rules[1]['rule'](self.report, fields) + self.assertEqual(result, "For the lowest fare you have provided, your maximum in-policy fare amount is 300 USD.") + + def test_pre_flight_section_lowest_fare_check_less_than_ten(self): + fields = {'lowest_fare_duration':10,'preferred_flight_duration':2,'lowest_fare':100,'preferred_flight_fare':1000} + result = pol.sections[1].rules[1]['rule'](self.report, fields) + self.assertEqual(result, "For the lowest fare you have provided, your maximum in-policy fare amount is 450 USD.") + + def test_pre_flight_section_lowest_fare_check_other(self): + fields = {'lowest_fare_duration':12,'preferred_flight_duration':1,'lowest_fare':100,'preferred_flight_fare':1000} + result = pol.sections[1].rules[1]['rule'](self.report, fields) + self.assertEqual(result, "For the lowest fare you have provided, your maximum in-policy fare amount is 700 USD.") + + def test_pre_flight_section_departure_date_too_late(self): + fields = {'departure_date':'2019-03-13','screenshot_date':'2019-03-01'} + result = pol.sections[1].rules[2]['rule'](self.report, fields) + self.assertEqual(result, "Flights must be booked at least 14 days in advance.") + + def test_pre_flight_section_departure_date_too_early(self): + fields = {'departure_date':'2020-03-10','screenshot_date':'2019-03-01'} + result = pol.sections[1].rules[2]['rule'](self.report, fields) + self.assertEqual(result, "Flights must be booked no more than 365 days in advance.") + + def test_flight_info_section_fare_limit_domestic(self): + fields = {'fare':751,'international_flight':False} + result = pol.sections[2].rules[0]['rule'](self.report, fields) + self.assertEqual(result, "Fares for domestic flights over 750 USD require Conservancy pre-approval, even if other policy conditions have been met.") + + def test_flight_info_section_fare_limit_international(self): + fields = {'fare':1651,'international_flight':True} + result = pol.sections[2].rules[0]['rule'](self.report, fields) + self.assertEqual(result, "Fares for international flights over 1,650 USD require Conservancy pre-approval, even if other policy conditions have been met.") + + def test_flight_info_section_request_date(self): + fields = {'return_date':'2018-01-01'} + result = pol.sections[2].rules[1]['rule'](self.report, fields) + self.assertEqual(result, "Reimbursement requests must be made within 90 days of the last day of travel.") + + def test_hotels_lodging_section_average_nightly_rate(self): + fields = {'check_in_date':'2019-03-01','check_out_date':'2019-03-11','cost':1100,'per_diem_rate':100} + result = pol.sections[3].rules[0]['rule'](self.report, fields) + self.assertEqual(result, "The average nightly rate cannot exceed the U.S. GSA rate.") + + def test_other_expenses_section_per_diem_check(self): + fields = {'rate':100,'full_days':3,'partial_days':2,'cost':451} + result = pol.sections[5].rules[0]['rule'](self.report, fields) + self.assertEqual(result, "You may only request a maximum of 450.0 USD for the rate and trip duration provided.") diff --git a/back/backend/tests.py b/back/backend/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/back/backend/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. From 6cd7903555c78fe8e71a440e7eea5052233a6b74 Mon Sep 17 00:00:00 2001 From: Joe Arriaga Date: Sat, 2 Mar 2019 20:37:38 -0800 Subject: [PATCH 02/18] Added economy class check to policy.py file. --- back/backend/policy.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/back/backend/policy.py b/back/backend/policy.py index 41f8b73..b143304 100644 --- a/back/backend/policy.py +++ b/back/backend/policy.py @@ -97,6 +97,7 @@ planning_section = Section( "preferred_flight_fare": {"number": 6, "label": "Fare of your preferred flight", "field_type": "decimal"}, "preferred_flight_duration": {"number": 7, "label": "Flight duration of your preferred flight (hours)", "field_type": "decimal"}, "international_flight": {"number": 8, "label": "Is this an international flight?", "field_type": "boolean"}, + "economy_class": {"number": 9, "label": "Is your ticket in economy/coach?", "field_type": "boolea n"}, } ) @@ -142,6 +143,12 @@ def departure_date_limit_rule(report, fields): return None planning_section.add_rule(title="Departure date limit", rule=departure_date_limit_rule) + +def economy_class_rule(report, fields): + if not economy_class: + return "Only economy or coach class tickets are within policy." + +planning_section.add_rule(title="Economy class check", rule=economy_class_rule) pol.add_section(planning_section) #### Flight Info From dac67f8fc60b849041419b4cb4df461f7ac3800c Mon Sep 17 00:00:00 2001 From: Rupika Date: Sun, 3 Mar 2019 12:59:26 -0800 Subject: [PATCH 03/18] added finalize report api function & url --- back/backend/urls.py | 1 + back/backend/views.py | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/back/backend/urls.py b/back/backend/urls.py index 83f7279..ac68cb8 100644 --- a/back/backend/urls.py +++ b/back/backend/urls.py @@ -8,6 +8,7 @@ urlpatterns = [ path('report', views.report), path('reports', views.reports), path('report/', views.report_detail), + path('report//final', views.finalize_report), path('report//section/', views.section), ] diff --git a/back/backend/views.py b/back/backend/views.py index d31728f..6d28f4f 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -3,8 +3,6 @@ from django.http import JsonResponse from .models import * from .policy import pol import os -from rest_framework.exceptions import ParseError -from rest_framework.parsers import FileUploadParser, MultiPartParser from django.core.mail import EmailMultiAlternatives from django.template.loader import render_to_string from decouple import config @@ -99,7 +97,6 @@ def get_fields(s_id): return field_set - def generate_named_fields_for_section(fields): """ Prepares a dictionary of key-value pairs based on the raw fields @@ -205,17 +202,17 @@ def report_detail(request, report_pk): return JsonResponse(data) # PUT: Submits a report to the administrator for review, - # and marks it as "submitted", after which changes may - # not be made. + # but is still allowed to make further changes elif request.method == 'PUT': - rep = Report.objects.get(id=report_pk) - if rep.submitted == True: - return JsonResponse({"message": "Cannot submit a report that has already been submitted."}, status=409) - rep.submitted = True; - rep.save() + # rep = Report.objects.get(id=report_pk) + # if rep.submitted: + # return JsonResponse({"message": "Cannot submit a report that has already been submitted."}, status=409) + # rep.submitted = True + # rep.save() + # Send email send_report_to_admin(request, report_pk) - return JsonResponse({"message": "Report submitted."}) + return JsonResponse({"message": "Report submitted for review."}) # DELETE: Deletes a report from the user's account. elif request.method == 'DELETE': @@ -237,6 +234,26 @@ def report_detail(request, report_pk): r.delete() return JsonResponse({"message": "Deleted report: {0}.".format(title)}) +@api_view(['PUT']) +def finalize_report(request, report_pk): + """ + This function serves as an API endpoint for submitting + the final report. + + :param request: incoming request packet + :param report_pk: report ID + :return: JSON response containing user message + """ + r = Report.objects.get(id=report_pk) + if r.submitted: + return JsonResponse({"message": "Cannot submit a report that has already been submitted."}, status=409) + r.submitted = True + r.save() + # Send email + send_report_to_admin(request, report_pk) + return JsonResponse({"message": "Final report submitted."}) + + def user_owns_section(user, section): """ Returns true if the specified user is owner of the section. From c8286778bc4a35e8843116bffda56c96ee53f8dd Mon Sep 17 00:00:00 2001 From: Rupika Date: Sun, 3 Mar 2019 14:46:12 -0800 Subject: [PATCH 04/18] change report() function in views to create_report() --- back/.env | 8 ++++---- back/backend/urls.py | 2 +- back/backend/views.py | 2 +- back/db.sqlite3 | Bin 84992 -> 99328 bytes 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/back/.env b/back/.env index 3b79ce5..ad0991e 100644 --- a/back/.env +++ b/back/.env @@ -1,4 +1,4 @@ -EMAIL_HOST_USER=accountemail@youremail.com -EMAIL_HOST_PASSWORD=yourpassword -SUBMIT_REPORT_DESTINATION_EMAIL=administratoremail@yourmail.com -SUBMIT_REPORT_FROM_EMAIL=from-address@yourmail.com +EMAIL_HOST_USER=reimbursinator@gmail.com +EMAIL_HOST_PASSWORD=Frank12345 +SUBMIT_REPORT_DESTINATION_EMAIL=rdikkala@pdx.edu +SUBMIT_REPORT_FROM_EMAIL=rdikkala@pdx.edu diff --git a/back/backend/urls.py b/back/backend/urls.py index ac68cb8..33eb2f6 100644 --- a/back/backend/urls.py +++ b/back/backend/urls.py @@ -5,7 +5,7 @@ from rest_framework.urlpatterns import format_suffix_patterns from . import views urlpatterns = [ - path('report', views.report), + path('report', views.create_report), path('reports', views.reports), path('report/', views.report_detail), path('report//final', views.finalize_report), diff --git a/back/backend/views.py b/back/backend/views.py index 6d28f4f..6ea167c 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -112,7 +112,7 @@ def generate_named_fields_for_section(fields): return result @api_view(['POST']) -def report(request): +def create_report(request): """ Generates a new empty report for the current user and returns it in json format. The title of the report should be provided as diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 06e1e06f8dd05a52663e78a4ff898a8795cf8fc9..6adb3fa18b92f3a73da7bb6f0c7136697c13360c 100644 GIT binary patch literal 99328 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 From 09813acf301135f3d4d60287e818ec792e8950f2 Mon Sep 17 00:00:00 2001 From: Rupika Date: Sun, 3 Mar 2019 15:16:38 -0800 Subject: [PATCH 05/18] added review/final status to email subject --- back/.env | 8 ++++---- back/backend/views.py | 18 ++++++------------ back/db.sqlite3 | Bin 99328 -> 113664 bytes 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/back/.env b/back/.env index ad0991e..fbac74c 100644 --- a/back/.env +++ b/back/.env @@ -1,4 +1,4 @@ -EMAIL_HOST_USER=reimbursinator@gmail.com -EMAIL_HOST_PASSWORD=Frank12345 -SUBMIT_REPORT_DESTINATION_EMAIL=rdikkala@pdx.edu -SUBMIT_REPORT_FROM_EMAIL=rdikkala@pdx.edu +EMAIL_HOST_USER=accountemail@yourmail.com +EMAIL_HOST_PASSWORD=accountpasswordhere +SUBMIT_REPORT_DESTINATION_EMAIL=to-address@yourmail.com +SUBMIT_REPORT_FROM_EMAIL=from-address@yourmail.com \ No newline at end of file diff --git a/back/backend/views.py b/back/backend/views.py index 6ea167c..38fc01f 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -204,15 +204,9 @@ def report_detail(request, report_pk): # PUT: Submits a report to the administrator for review, # but is still allowed to make further changes elif request.method == 'PUT': - # rep = Report.objects.get(id=report_pk) - # if rep.submitted: - # return JsonResponse({"message": "Cannot submit a report that has already been submitted."}, status=409) - # rep.submitted = True - # rep.save() - # Send email - send_report_to_admin(request, report_pk) - return JsonResponse({"message": "Report submitted for review."}) + send_report_to_admin(request, report_pk, status="REVIEW") + return JsonResponse({"message": "Request for review is submitted."}) # DELETE: Deletes a report from the user's account. elif request.method == 'DELETE': @@ -250,7 +244,7 @@ def finalize_report(request, report_pk): r.submitted = True r.save() # Send email - send_report_to_admin(request, report_pk) + send_report_to_admin(request, report_pk, status="FINAL") return JsonResponse({"message": "Final report submitted."}) @@ -400,7 +394,7 @@ def section_complete(section_pk): return True return False -def send_report_to_admin(request, report_pk): +def send_report_to_admin(request, report_pk, status): """ Sends an email message to admin with html/txt version of report, along with file attachments. Cc sent to user. @@ -417,7 +411,7 @@ def send_report_to_admin(request, report_pk): message = None if params['reference_number'] == '': message = EmailMultiAlternatives( - "{}".format(params['title']), + "{}: {}".format(status, params['title']), msg_plain, from_email, [to_email], @@ -425,7 +419,7 @@ def send_report_to_admin(request, report_pk): ) else: message = EmailMultiAlternatives( - "[RT - Request Tracker #{}] {}".format(params['reference_number'], params['title']), + "[{} - Request #{}] {}".format(status, params['reference_number'], params['title']), msg_plain, from_email, [to_email], diff --git a/back/db.sqlite3 b/back/db.sqlite3 index 6adb3fa18b92f3a73da7bb6f0c7136697c13360c..c601b715009e890600773bcf4d48198f51e2cedd 100644 GIT binary patch delta 4774 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 kiL Date: Mon, 4 Mar 2019 00:36:36 -0800 Subject: [PATCH 06/18] Add createCollapsibleCard and createCollapsibleCardBody tests --- front/static/js/viewHistory.js | 10 +-- front/static/tests/qunit_tests.html | 107 +++++++++++++++++++++++----- 2 files changed, 95 insertions(+), 22 deletions(-) diff --git a/front/static/js/viewHistory.js b/front/static/js/viewHistory.js index 97b4884..3e5b7f7 100644 --- a/front/static/js/viewHistory.js +++ b/front/static/js/viewHistory.js @@ -86,7 +86,7 @@ function updateSection(parsedData, saveButton) { saveButton.innerHTML = "Save"; saveButton.disabled = false; - + } // Wraps a Bootstrap form group around a field @@ -214,7 +214,7 @@ function createCollapsibleCard(sectionIdStr, sectionTitle, sectionCompleted, rul sectionState.classList.add("fas", "fa-exclamation-triangle"); } } - + // Create h2, button. Append button to h2, h2 to header, and header to card const h2 = document.createElement("h2"); h2.classList.add("mb-0"); @@ -232,7 +232,7 @@ function createCollapsibleCard(sectionIdStr, sectionTitle, sectionCompleted, rul return card; } -function createCollapsibleCardBody(form, type, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations) { +function createCollapsibleCardBody(form, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations) { // Create wrapper div const collapseDiv = document.createElement("div"); collapseDiv.id = sectionIdStr + "collapse"; @@ -284,7 +284,7 @@ function createCardFooter(ruleViolations) { violation.appendChild(ruleBreakText); violationMessage.appendChild(violation); } - + cardFooter.appendChild(violationMessage); return cardFooter; } @@ -358,7 +358,7 @@ function createReportForm(parsedData, type) { form.appendChild(saveButton); // Create collapsible card body, append form to it, append card to accordion - let cardBody = createCollapsibleCardBody(form, type, sectionIdStr, + let cardBody = createCollapsibleCardBody(form, sectionIdStr, sections[i].html_description, sections[i].completed, sections[i].rule_violations); let cardFooter = createCardFooter(sections[i].rule_violations); if (cardFooter) { diff --git a/front/static/tests/qunit_tests.html b/front/static/tests/qunit_tests.html index b751c4a..a1635d4 100644 --- a/front/static/tests/qunit_tests.html +++ b/front/static/tests/qunit_tests.html @@ -27,8 +27,8 @@ let formGroup = createFormGroup(sectionIdStr, field); let expectedHTML = `
` - assert.deepEqual(formGroup.outerHTML, expectedHTML, "boolean false renders as no option selected"); - + assert.deepEqual(formGroup.outerHTML, expectedHTML, "boolean false renders as no option selected"); + }); QUnit.test("boolean input group true renders", function(assert) { @@ -42,12 +42,12 @@ let formGroup = createFormGroup(sectionIdStr, field); let expectedHTML = `
` - assert.deepEqual(formGroup.outerHTML, expectedHTML, "boolean true renders as yes option selected"); + assert.deepEqual(formGroup.outerHTML, expectedHTML, "boolean true renders as yes option selected"); }); // END: Test rendering of fields with type boolean - + // BEGIN: Test rendering of fields with type date QUnit.test("date input group renders", function(assert) { let sectionIdStr = "section-1-"; @@ -59,7 +59,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let expectedHTML = `
` - assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string"); + assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string"); }); QUnit.test("date value None", function(assert) { @@ -72,7 +72,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let value = formGroup.querySelector("#section-1-departure_date").value; - assert.deepEqual(value, "", "date initialized to None has null value"); + assert.deepEqual(value, "", "date initialized to None has null value"); }); QUnit.test("date value assignment", function(assert) { @@ -85,7 +85,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let value = formGroup.querySelector("#section-1-departure_date").value; - assert.deepEqual(value, field.value, "date input initialized to a value is rendered with that value"); + assert.deepEqual(value, field.value, "date input initialized to a value is rendered with that value"); }); // END: Test rendering of fields with type date @@ -100,7 +100,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let expectedHTML = `
` - assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string"); + assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string"); }); QUnit.test("string value assignment", function(assert) { @@ -113,7 +113,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let value = formGroup.querySelector("#section-1-city").value; - assert.deepEqual(value, field.value, "text input initialized to a value is rendered with that value"); + assert.deepEqual(value, field.value, "text input initialized to a value is rendered with that value"); }); // END: Test rendering of fields with type date @@ -128,7 +128,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let expectedHTML = `
` - assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string"); + assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string"); }); QUnit.test("decimal input group initialized to default", function(assert) { @@ -141,7 +141,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let value = formGroup.querySelector("#section-1-lowest_fare").value; - assert.deepEqual(value, "", "decimal input initialized to 0.00 has null value"); + assert.deepEqual(value, "", "decimal input initialized to 0.00 has null value"); }); QUnit.test("decimal input group initialized to value", function(assert) { @@ -154,7 +154,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let value = formGroup.querySelector("#section-1-lowest_fare").value; - assert.deepEqual(value, field.value, "decimal input initialized to 1337 has value 1337"); + assert.deepEqual(value, field.value, "decimal input initialized to 1337 has value 1337"); }); // END: Test rendering of fields with type decimal @@ -169,7 +169,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let expectedHTML = `
` - assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string"); + assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string"); }); QUnit.test("integer input group initialized to default", function(assert) { @@ -182,7 +182,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let value = formGroup.querySelector("#section-1-full_days").value; - assert.deepEqual(value, "", "integer input initialized to 0 has null value"); + assert.deepEqual(value, "", "integer input initialized to 0 has null value"); }); QUnit.test("integer input group initialized to value", function(assert) { @@ -195,7 +195,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let value = formGroup.querySelector("#section-1-full_days").value; - assert.deepEqual(value, field.value.toString(), "integer input initialized to 1234 has string value 1234"); + assert.deepEqual(value, field.value.toString(), "integer input initialized to 1234 has string value 1234"); }); // END: Test rendering of fields with type integer @@ -211,7 +211,7 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let expectedHTML = `

` - assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string"); + assert.deepEqual(formGroup.outerHTML, expectedHTML, "formGroup string matches expectedHTML string"); }); QUnit.test("file input group form text assignment", function(assert) { @@ -224,10 +224,83 @@ }; let formGroup = createFormGroup(sectionIdStr, field); let value = formGroup.querySelector(".form-text").innerHTML; - assert.deepEqual(value, field.value, "file input initialized to screenshot.jpg has string value screenshot.jpg"); + assert.deepEqual(value, field.value, "file input initialized to screenshot.jpg has string value screenshot.jpg"); }); // END: Test rendering of fields with type file + // BEGIN createCollapsibleCard unit tests + QUnit.module("createCollapsibleCard"); + + QUnit.test("incomplete section renders", function(assert) { + let sectionIdStr = "section-1-"; + let sectionTitle = "General Info"; + let sectionCompleted = false; + let ruleViolations = []; + + let card = createCollapsibleCard(sectionIdStr, sectionTitle, sectionCompleted, ruleViolations); + let expectedHTML = `

`; + assert.deepEqual(card.outerHTML, expectedHTML, "card html and expectedHTML are identical"); + }); + + QUnit.test("complete section with no rule violations renders", function(assert) { + let sectionIdStr = "section-1-"; + let sectionTitle = "General Info"; + let sectionCompleted = true; + let ruleViolations = []; + + let card = createCollapsibleCard(sectionIdStr, sectionTitle, sectionCompleted, ruleViolations); + let expectedHTML = `

` + assert.deepEqual(card.outerHTML, expectedHTML, "card html and expectedHTML are identical"); + }); + + QUnit.test("complete section with a violation renders", function(assert) { + let sectionIdStr = "section-1-"; + let sectionTitle = "General Info"; + let sectionCompleted = true; + let ruleViolations = [{"label": "Fare limits", "rule_break_text": "You did a bad thing"}] + + let card = createCollapsibleCard(sectionIdStr, sectionTitle, sectionCompleted, ruleViolations); + let expectedHTML = `

` + assert.deepEqual(card.outerHTML, expectedHTML, "card html and expectedHTML are identical"); + }); + + + // BEGIN createCollapsibleCard unit tests + QUnit.module("createCollapsibleCardBody"); + // form, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations + + QUnit.test("incomplete section renders", function(assert) { + let form = document.createElement("form"); + let sectionIdStr = "section-1-"; + let sectionDescription = "

Section Description

"; + let sectionCompleted = false; + let ruleViolations = []; + let collapseDiv = createCollapsibleCardBody(form, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations); + let expectedHTML = `
This section is not complete

Section Description

`; + assert.deepEqual(collapseDiv.outerHTML, expectedHTML, "collapseDiv html and expectedHTML are identical"); + }); + + QUnit.test("complete section with no rule violations renders", function(assert) { + let form = document.createElement("form"); + let sectionIdStr = "section-1-"; + let sectionDescription = "

Section Description

"; + let sectionCompleted = true; + let ruleViolations = []; + let collapseDiv = createCollapsibleCardBody(form, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations); + let expectedHTML = `

Section Description

`; + assert.deepEqual(collapseDiv.outerHTML, expectedHTML, "collapseDiv html and expectedHTML are identical"); + }); + + QUnit.test("complete section with rule violation renders", function(assert) { + let form = document.createElement("form"); + let sectionIdStr = "section-1-"; + let sectionDescription = "

Section Description

"; + let sectionCompleted = true; + let ruleViolations = [{"label": "Fare limits", "rule_break_text": "You did a bad thing"}] + let collapseDiv = createCollapsibleCardBody(form, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations); + let expectedHTML = `

Section Description

`; + assert.deepEqual(collapseDiv.outerHTML, expectedHTML, "collapseDiv html and expectedHTML are identical"); + }); From f250e3addaeaf910ac803e7b526b2cdd85224f40 Mon Sep 17 00:00:00 2001 From: Preston Doman Date: Mon, 4 Mar 2019 13:32:18 -0800 Subject: [PATCH 07/18] Add createCardFooter tests --- front/static/tests/qunit_tests.html | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/front/static/tests/qunit_tests.html b/front/static/tests/qunit_tests.html index a1635d4..6d4ca4b 100644 --- a/front/static/tests/qunit_tests.html +++ b/front/static/tests/qunit_tests.html @@ -267,7 +267,6 @@ // BEGIN createCollapsibleCard unit tests QUnit.module("createCollapsibleCardBody"); - // form, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations QUnit.test("incomplete section renders", function(assert) { let form = document.createElement("form"); @@ -301,6 +300,29 @@ let expectedHTML = `

Section Description

`; assert.deepEqual(collapseDiv.outerHTML, expectedHTML, "collapseDiv html and expectedHTML are identical"); }); + + // BEGIN createCardFooter unit tests + QUnit.module("createCardFooter"); + + QUnit.test("card footer no rule violations does not render", function(assert) { + let ruleViolations = []; + let cardFooter = createCardFooter(ruleViolations); + assert.strictEqual(cardFooter, null, "cardFooter is null"); + }); + + QUnit.test("card footer with one rule violation renders", function(assert) { + let ruleViolations = [{"label": "Fare limits", "rule_break_text": "You did a bad thing"}]; + let cardFooter = createCardFooter(ruleViolations); + let expectedHTML = ``; + assert.deepEqual(cardFooter.outerHTML, expectedHTML, "cardFooter html and expectedHTML are identical"); + }); + + QUnit.test("card footer with multiple rule violation renders", function(assert) { + let ruleViolations = [{"label": "Fare limits", "rule_break_text": "You did a bad thing"}, {"label": "Fare limits", "rule_break_text": "Now you've done it"}]; + let cardFooter = createCardFooter(ruleViolations); + let expectedHTML = ``; + assert.deepEqual(cardFooter.outerHTML, expectedHTML, "cardFooter html and expectedHTML are identical"); + }); From 839edcf7949bc1c0f7fbb15e4131ddf6424975b4 Mon Sep 17 00:00:00 2001 From: Preston Doman Date: Mon, 4 Mar 2019 15:34:03 -0800 Subject: [PATCH 08/18] Add createReportForm tests --- front/static/js/testObjects.js | 38 +++++++++++++++ front/static/tests/qunit_tests.html | 76 ++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 front/static/js/testObjects.js diff --git a/front/static/js/testObjects.js b/front/static/js/testObjects.js new file mode 100644 index 0000000..2063aab --- /dev/null +++ b/front/static/js/testObjects.js @@ -0,0 +1,38 @@ +const testReport = {"title": "New Report 1", "report_pk": 2, "date_submitted": "2019-03-04T08:00:00Z", "sections": [{"title": "General Info", "rule_violations": [], "fields": [{"field_type": "boolean", "label": "Have you taken this trip already?", "field_name": "after_trip", "value": false}], "completed": false, "id": 10, "html_description": "

Each section of this report is designed to guide you through the reimbursement process. Please read through each and answer as many questions as you can that apply to you.

Be sure to click 'Save' after completing each section. Your entered data will be saved as you progress. You may also receive feedback from sections regarding policy restrictions and special requirements.

"}, {"title": "Pre-trip Planning", "rule_violations": [], "fields": [{"field_type": "date", "label": "Departure date", "field_name": "departure_date", "value": "None"}, {"field_type": "date", "label": "Return date", "field_name": "return_date", "value": "None"}, {"field_type": "file", "label": "Screenshot of least expensive ticket fare", "field_name": "screenshot", "value": ""}, {"field_type": "date", "label": "Date of screenshot", "field_name": "screenshot_date", "value": "None"}, {"field_type": "decimal", "label": "Lowest fare", "field_name": "lowest_fare", "value": "0.00"}, {"field_type": "decimal", "label": "Flight duration of lowest fare (hours)", "field_name": "lowest_fare_duration", "value": "0.00"}, {"field_type": "decimal", "label": "Fare of your preferred flight", "field_name": "preferred_flight_fare", "value": "0.00"}, {"field_type": "decimal", "label": "Flight duration of your preferred flight (hours)", "field_name": "preferred_flight_duration", "value": "0.00"}, {"field_type": "boolean", "label": "Is this an international flight?", "field_name": "international_flight", "value": false}], "completed": false, "id": 11, "html_description": "

At least 14 days before buying tickets for your trip, take a screenshot of a flight search showing the least expensive fare available for the dates you need to travel. Include fares from multiple airlines if possible. This information will be used to calculate reimbursable fare amounts.

"}, {"title": "Flight Info", "rule_violations": [], "fields": [{"field_type": "date", "label": "Actual departure date", "field_name": "departure_date", "value": "None"}, {"field_type": "date", "label": "Actual return date", "field_name": "return_date", "value": "None"}, {"field_type": "decimal", "label": "Ticket fare", "field_name": "fare", "value": "0.00"}, {"field_type": "file", "label": "Screenshot of confirmation of purchase", "field_name": "confirmation_screenshot", "value": ""}, {"field_type": "boolean", "label": "Was this an international flight?", "field_name": "international_flight", "value": false}], "completed": false, "id": 12, "html_description": "

Enter the details of your flight once you have made your purchase.

"}, {"title": "Hotel / Lodging", "rule_violations": [], "fields": [{"field_type": "decimal", "label": "USGSA Per diem rate", "field_name": "per_diem_rate", "value": "0.00"}, {"field_type": "decimal", "label": "Total cost for lodging", "field_name": "cost", "value": "0.00"}, {"field_type": "date", "label": "Check-in date", "field_name": "check_in_date", "value": "None"}, {"field_type": "date", "label": "Check-out date", "field_name": "check_out_date", "value": "None"}, {"field_type": "file", "label": "Screenshot of invoice", "field_name": "invoice_screenshot", "value": ""}], "completed": false, "id": 13, "html_description": "

Please submit a receipt from your hotel including both the total amount and the dates of your stay. Per diem rates can be found on the U.S. GSA website.

"}, {"title": "Local Transportation", "rule_violations": [], "fields": [{"field_type": "decimal", "label": "Total cost of local transportation", "field_name": "cost", "value": "0.00"}], "completed": false, "id": 14, "html_description": "

This amount includes taxis, uber, and public transportation.

"}, {"title": "Per Diem and Other Expenses", "rule_violations": [], "fields": [{"field_type": "decimal", "label": "Per diem rate", "field_name": "rate", "value": "0.00"}, {"field_type": "integer", "label": "Number of full days of travel", "field_name": "full_days", "value": 0}, {"field_type": "integer", "label": "Number of partial days of travel", "field_name": "partial_days", "value": 0}, {"field_type": "decimal", "label": "Total Cost for meals and incidentals", "field_name": "cost", "value": "0.00"}], "completed": false, "id": 15, "html_description": "

Your per diem allowance is used to cover meals and incidental expenses. The rate for your travel destination can be found on the following websites:

You may request up to 100% of the listed rate for a full day of travel, or 75% for a partial day of travel."}, {"title": "Payment Option - Paypal", "rule_violations": [], "fields": [{"field_type": "string", "label": "Email address used with Paypal", "field_name": "paypal_email", "value": ""}, {"field_type": "string", "label": "Preferred currency", "field_name": "preferred_currency", "value": ""}], "completed": false, "id": 16, "html_description": "

Complete this section if you wish to be reimbursed via Paypal. This is the preferred reimbursement method of Software Freedom Conservancy.

"}, {"title": "Payment Option - Check", "rule_violations": [], "fields": [{"field_type": "string", "label": "Street address", "field_name": "address_1", "value": ""}, {"field_type": "string", "label": "Street address 2", "field_name": "address_2", "value": ""}, {"field_type": "string", "label": "City", "field_name": "city", "value": ""}, {"field_type": "string", "label": "State", "field_name": "state", "value": ""}, {"field_type": "string", "label": "Zip code", "field_name": "zip", "value": ""}], "completed": false, "id": 17, "html_description": "

Complete this section if you wish to be reimbursed in USD via check sent by mail.

"}, {"title": "Payment Option - Bank Wire", "rule_violations": [], "fields": [{"field_type": "string", "label": "Full name of account holder", "field_name": "name", "value": ""}, {"field_type": "string", "label": "Street address", "field_name": "address_1", "value": ""}, {"field_type": "string", "label": "Street address 2", "field_name": "address_2", "value": ""}, {"field_type": "string", "label": "City", "field_name": "city", "value": ""}, {"field_type": "string", "label": "State", "field_name": "state", "value": ""}, {"field_type": "string", "label": "Zip code", "field_name": "zip", "value": ""}, {"field_type": "string", "label": "Account number", "field_name": "account", "value": ""}, {"field_type": "string", "label": "Preferred currency", "field_name": "currency", "value": ""}, {"field_type": "string", "label": "Bank name", "field_name": "bank_name", "value": ""}, {"field_type": "string", "label": "Bank address", "field_name": "bank_address", "value": ""}, {"field_type": "string", "label": "Bank ACH/ABA routing number (US) or SWIFT/BIC code (non-US)", "field_name": "routing_number", "value": ""}, {"field_type": "string", "label": "Additional information (see SFC policy)", "field_name": "additional_info", "value": ""}], "completed": false, "id": 18, "html_description": "

Complete this section if you wish to be wired the amount to your bank in your local currency. Please fill in as much of the following information as is possible. Please refer to the SFC travel policy for additional bank information required for certain countries.

"}], "submitted": false, "reference_number": "1234", "date_created": "2019-03-04T08:00:00Z"}; + +const typeNewExpectedHTML = ``; + +const typeEditExpectedHTML = ``; \ No newline at end of file diff --git a/front/static/tests/qunit_tests.html b/front/static/tests/qunit_tests.html index 6d4ca4b..d1a2191 100644 --- a/front/static/tests/qunit_tests.html +++ b/front/static/tests/qunit_tests.html @@ -5,10 +5,61 @@ +
-
+
+ + +
From eec0af4211a273be68cac243616110a897e8dd8e Mon Sep 17 00:00:00 2001 From: Rupika Date: Mon, 4 Mar 2019 16:45:52 -0800 Subject: [PATCH 09/18] fixed email subject line --- back/backend/views.py | 4 ++-- back/db.sqlite3 | Bin 113664 -> 119808 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/back/backend/views.py b/back/backend/views.py index 38fc01f..d9997a1 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -411,7 +411,7 @@ def send_report_to_admin(request, report_pk, status): message = None if params['reference_number'] == '': message = EmailMultiAlternatives( - "{}: {}".format(status, params['title']), + "{} ({})".format(params['title'], status), msg_plain, from_email, [to_email], @@ -419,7 +419,7 @@ def send_report_to_admin(request, report_pk, status): ) else: message = EmailMultiAlternatives( - "[{} - Request #{}] {}".format(status, params['reference_number'], params['title']), + "[Reimbursinator #{}] {} ({})".format(params['reference_number'], params['title'], status), msg_plain, from_email, [to_email], diff --git a/back/db.sqlite3 b/back/db.sqlite3 index c601b715009e890600773bcf4d48198f51e2cedd..650f269d06fa861c3d89124f266123d7c73ad56e 100644 GIT binary patch delta 2196 zcmb`HYiv|S6vyYxnY~?TS*WO~M(Q@mqqN;ScX#ilTd-Q{3#w2Mqp0+?Ep4IiZV@a} zX9EgqB6VX&Q51p?G?)}t*^~y2N}^Fwt40uGMT>6~A5^8FICrlajT-&nm;Z0>ncQ>F z{Lh(t^N-ri+fp{1tzjA=q@&wgNHJ|kMR;@$xKDFqHdIxHm(?^?m$%ilG`B^x@#&cJ zd#t@C9I0<^vf^KjE|@yb^m1Mh^cR>xpJDKz5zi02+Tb2mX-ORp$32@r!Bn-b)evYF z*|_r|HqPV1A%Z7x7?0v-I22DmX8>b^TQlM(63?d;<%h%EpI=!Sv;qMhn$AOhBWzV0 zR&}7ttjS+u1Ve`3GQxgtgz|VGkN=?nK0O%VM*P$>2XV@OOtW(@WA3r|lwEJ6yCpN0 zzA+pg*-9kH|n88Y*J(Bjh$L@`5!+C+!a zR#C6CSu9rCDCWlZzB@v_({Bj1)~+<0BQ<V8<$1(cj1$M86Q zi(lYjd=KBo*YHJr7I$MDx8uY307~3|>y>$(7{Nwdg5`J(&c``ej5AdlKjz?hI04VZ zv8r1@N9cF-2>pl*YN(#_h&`JoIcY;D?>kU?Kz-yr4HK!G;1%dn{&>^?+hH%c*M
J2$`t zIlLRzA{Q6Q(nX-lvTYDd)bD^Gb-9RF%#}tjWTawyq^-WGHg|?7lIzw(fjkulmt?Ep zY49a3tAP8|MNE|Mf=6Hy86h};Pv9z5L>fIv6LcM&L;+rc2cZ=T)wU$FyNfbL>!QL# zva?G>x!l(ZbC_Ns%4EyqP|oxsu~?Q>!-dSp#r5*_t*Wjo`rs+KsUN}#x*JwNPaS*+ zemPVJVWvgL7>POckOrt#a=BvKhC;(infoWPHA;m)G3}rHoG& zb@J4Dn8Y|2wXxmdwARx6*1l35K8#+R5Fd zjm#%`xC2*{EU`*{&%OD7@Uv4*}{xs(INN5U=|BZ5fQn)8z!^B1)^PU>4ZWSm?_%i>KM$hSFN%vu2z07 zTIArZ7v7rpUz`z&FaujcOip zZuTfyd6%-l%8I&dzrD-~MwxuP4+6}}jAHV7G0PjJw%6w}%NGT?rCM2FRYZy0+^@}KRP?x&OQQBC?YCJGD7;$xeuLdo2isVkXlGL zK{DZpC>dB8bfG)oDFchxRf?5jpE5)O6-sYXN-ykq6J7)b@6GeT^Srilub{moZ$7}L=ngfw=p|YIn zGNoIxM2pKTxNPPkt7tXb6^CW=qJB-Qn5az+;KS23E0x zCB>NY3CfZ>qbrr{ev3z}u}Pxj5CqY0ce=ecM~&C#v6&^&>#h;Ke#t3{g4tOpShU%; zT972Gq-?(UjNJdMiN$$dZ$NyDG~C&c5j7iR_4#p1K{P&If*goZ-NaE1Z=OZPH&YsP z8i!YCM=8=YcY`Tu)4#SF#3!v0_& z*yt1ezTlPmh9;*_S9>|+RuTy#8SUFHu~?lJTWoF)|IEg|uHY}xMSch+tXe}s zu~7<#b^O3G7BP=myvJL-MjT^!iWr{YA^OpSF5E!}ZlDF1P!A8z;WWx{1SN3F6TOtd zvjqDf>wD>z_Nr_(rH>{_IdwmeM*4|QH|-#3|Dga$1f0blHq9QhdS;?;G)_I-6nB#= z=Zf%7E*K(FUKphZ5ZVsOCoAcId|{BRYG9bGj7)NQCFS5?Td7>|l3enpLP;t=LFbw3 z9-#r+PnjI9;TUq+8k=Dqtb&;tLmwsR5nZP;%GBsq<>F_wpxz#(7LxBNl#S}PGxB#o HRZ-z@rP}ER From 5ac57e88e23930bfb0e80f59fa053b5769999cee Mon Sep 17 00:00:00 2001 From: Preston Doman Date: Tue, 5 Mar 2019 15:58:41 -0800 Subject: [PATCH 10/18] Add displayListOfReports tests --- front/static/js/testObjects.js | 6 ++- front/static/js/viewHistory.js | 18 +++------ front/static/tests/qunit_tests.html | 59 ++++++++++++++++++++++++----- 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/front/static/js/testObjects.js b/front/static/js/testObjects.js index 2063aab..0278d85 100644 --- a/front/static/js/testObjects.js +++ b/front/static/js/testObjects.js @@ -35,4 +35,8 @@ const typeEditExpectedHTML = ` - `; \ No newline at end of file + `; + +const displayReportsOneReportExpected = `
TitleDate CreatedDate SubmittedAction
TEST13/5/2019TBD
`; + +const displayReportsTwoReportsExpected = `
TitleDate CreatedDate SubmittedAction
TEST13/5/2019TBD
TEST23/5/2019TBD
`; \ No newline at end of file diff --git a/front/static/js/viewHistory.js b/front/static/js/viewHistory.js index 3e5b7f7..055011d 100644 --- a/front/static/js/viewHistory.js +++ b/front/static/js/viewHistory.js @@ -295,12 +295,6 @@ function createReportForm(parsedData, type) { const accordion = document.createElement("div"); accordion.classList.add("accordion"); - //submit button - const submitButton = document.querySelector(".submit-report-button"); - if (submitButton) { - submitButton.setAttribute("data-rid", parsedData.report_pk); - } - if (type === reportType.EDIT) { modalBody = document.querySelector("#editReportModalBody"); modalLabel = document.querySelector("#editReportModalLabel"); @@ -317,6 +311,11 @@ function createReportForm(parsedData, type) { return; } + const submitButton = document.querySelector(".submit-report-button"); + if (submitButton) { + submitButton.setAttribute("data-rid", parsedData.report_pk); + } + while (modalBody.firstChild) { modalBody.removeChild(modalBody.firstChild); } @@ -339,13 +338,6 @@ function createReportForm(parsedData, type) { // Traverse the fields of this section let fields = sections[i].fields; for (let j = 0; j < fields.length; j++) { - - /* - console.log("Field label: " + fields[j].label); - console.log("Field type: " + fields[j].field_type); - console.log("Field value: " + fields[j].value); - */ - // Create a form group for each field and add it to the form form.appendChild(createFormGroup(sectionIdStr, fields[j])); } diff --git a/front/static/tests/qunit_tests.html b/front/static/tests/qunit_tests.html index d1a2191..ecd21d9 100644 --- a/front/static/tests/qunit_tests.html +++ b/front/static/tests/qunit_tests.html @@ -10,6 +10,23 @@
+
+
+ +
+ + + + + + + + + + + + +