Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Visitation Flow #247

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
534cb89
routing
rodrigotiscareno Jan 28, 2024
d0d0d14
tweak
rodrigotiscareno Jan 28, 2024
d8a01e9
Link and Integrate PUT Case Submission Pt. 1 (#237)
JennyVong Jan 28, 2024
df593f7
checkpoint
rodrigotiscareno Feb 25, 2024
1c259f8
checkpoint
rodrigotiscareno Feb 25, 2024
c75a85d
Add CreateVisitDTO class
helioshe4 Feb 25, 2024
25f7de8
database insertion work
rodrigotiscareno Mar 17, 2024
2ba274f
Revert "Link and Integrate PUT Case Submission Pt. 1 (#237)"
rodrigotiscareno Mar 31, 2024
30a3cac
ui tweaks
rodrigotiscareno Mar 31, 2024
be9d469
fixes for placeholders
rodrigotiscareno Apr 7, 2024
e036585
Merge branch 'main' into rt/visit-backend
May 2, 2024
7ebeb1f
Bug fixes on frontend about visitation data handling
May 2, 2024
d61cbcd
refresh validations to be less restrictive
rodrigotiscareno May 7, 2024
53b4409
install cancel logic
rodrigotiscareno May 7, 2024
6a9661e
fix visitation notes UI
rodrigotiscareno May 7, 2024
323be11
fix child and family support worker ui and functionality
rodrigotiscareno May 7, 2024
77ce02a
re-direct to home after submission
rodrigotiscareno May 16, 2024
90c9b38
Merge branch 'main' into rt/visit-backend
May 27, 2024
04c946a
Fixed visit data collection (Transportaion and Attendance mainly)
May 28, 2024
173ecdd
Added POST and GET requests
vaaranan-y Jul 6, 2024
215593a
fix buggy test
rodrigotiscareno Aug 11, 2024
d481cdd
visitation workflow tweaks
rodrigotiscareno Aug 11, 2024
732aaf9
make duration ui integer-based
rodrigotiscareno Aug 11, 2024
60ac3b1
fix enums for front-end
rodrigotiscareno Aug 11, 2024
83d3662
support transport and visiting member backend functionality
rodrigotiscareno Aug 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions backend/python/app/resources/visit_dto.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
class VisitDTO(object):
def __init__(self, **kwargs):
self.user_id = kwargs.get("user_id")
self.childInformation = kwargs.get("childInformation")
self.visitTimestamp = kwargs.get("visitTimestamp")
self.attendance = kwargs.get("attendance")
self.transportation = kwargs.get("transportation")
self.notes = kwargs.get("notes")
self.childAndFamilySupportWorker = kwargs.get("childAndFamilySupportWorker")
self.case_id = kwargs.get("case_id")
self.child_details = kwargs.get("child_details")
self.visit_details = kwargs.get("visit_details")
self.attendance = kwargs.get("attendance_entries")
self.transportation = kwargs.get("transportation_entries")
self.notes = kwargs.get("visit_notes")


class CreateVisitDTO(VisitDTO):
def __init__(self, **kwargs):
super().__init__(**kwargs)

def validate(self):
pass
error_list = []

if not self.user_id or not isinstance(self.user_id, int):
error_list.append("user_id is invalid")
if not self.child_details:
error_list.append("childInformation is invalid")
if not self.attendance:
error_list.append("attendance is invalid")

return error_list
40 changes: 34 additions & 6 deletions backend/python/app/rest/visit_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

from flask import Blueprint, current_app, jsonify, request

from ..middlewares.auth import require_authorization_by_role
from ..middlewares.validate import validate_request
from ..resources.visit_dto import VisitDTO
from ..resources.visit_dto import CreateVisitDTO
from ..services.implementations.visit_service import VisitService

# define instance of VisitService
Expand All @@ -15,7 +13,37 @@


@blueprint.route("/", methods=["POST"], strict_slashes=False)
@require_authorization_by_role({"User", "Admin"})
@validate_request("VisitDTO")
def create_visit():
pass
data = request.json

visit_data = {
"user_id": int(data.get("user_id")),
"case_id": data.get("case_id"),
"child_details": data.get("child_details"),
"visit_details": data.get("visit_details"),
"attendance_entries": data.get("attendance_entries"),
"transportation_entries": data.get("transportation_entries"),
"visit_notes": data.get("visit_notes"),
}

visit = CreateVisitDTO(**visit_data)
errors = visit.validate()
if errors:
return {"error": errors}, 400
try:
visit_service.create_visit(visit)
return jsonify({"message": "Visit created successfully"}), 201
except Exception as e:
return jsonify({"error": str(e)}), 500

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.


@blueprint.route("/<int:user_id>", methods=["GET"], strict_slashes=False)
def get_visit_by_user_id(user_id):
result = visit_service.get_visit_by_user_id(user_id)
merged_dict = {}
for dto in result:
merged_dict.update(dto.__dict__)
return (
jsonify(merged_dict),
200,
)
89 changes: 87 additions & 2 deletions backend/python/app/services/implementations/visit_service.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,95 @@
from ...models import db
from ..interfaces.visit_service import IVisitService
from ...resources.visit_dto import VisitDTO
from ...resources.attendance_sheet_dto import AttendanceSheetDTO
from ...resources.attendance_records_dto import AttendanceRecordsDTO
from ...models.attendance_sheets import AttendanceSheets
from ...models.attendance_records import AttendanceRecords
from ...models.attendance_records import VisitingMember
from ...models.attendance_records import Transportation
from ...models.transportation_method import TransportationMethod


class VisitService(IVisitService):
def __init__(self, logger):
self.logger = logger

def create_visit():
pass
def create_visit(self, visit: VisitDTO):
try:
attendance_sheet = AttendanceSheets(
family_name=visit.child_details["family_name"],
csw=visit.child_details["child_service_worker"],
cpw=visit.child_details["child_protection_worker"],
fcc=visit.child_details["foster_care_coordinator"],
)
db.session.add(attendance_sheet)
db.session.flush()

attendance_record = AttendanceRecords(
attendance_sheet_id=attendance_sheet.id,
visit_date=visit.visit_details["visit_date"],
visit_day=visit.visit_details["visit_day"],
visit_supervision=visit.visit_details["visit_supervision"].upper(),
start_time=visit.visit_details["start_time"],
end_time=visit.visit_details["end_time"],
location=visit.visit_details["location"],
notes=visit.notes,
)
db.session.add(attendance_record)
db.session.flush()

for visiting_member in visit.attendance["entries"]:
member = VisitingMember(
attendance_record_id=attendance_record.id,
visitor_relationship=visiting_member["visitor_relationship"],
visiting_member_name=visiting_member["visiting_member_name"],
description=visiting_member["description"],
visit_attendance=visiting_member["visit_attendance"],
reason_for_absence=visiting_member["absence_reason"],
)
db.session.add(member)

for transport in visit.transportation["entries"]:
transportation = Transportation(
attendance_record_id=attendance_record.id,
guardian=transport["guardian"],
name=transport["name"],
duration=transport["duration"],
)
db.session.add(transportation)

# TODO: Add a reference key to transportation method for the visit
# transportation_entry = visit.transportation["entries"][0]
# transportation_method_name = transportation_entry["name"]
# attendance_record.notes += (
# f" Transportation Method: {transportation_method_name}"
# )

db.session.commit()

return {"message": "Visit created successfully"}
except Exception as error:
db.session.rollback()
self.logger.error(f"Error creating visit: {error}")
raise error

def get_visit_by_user_id(self, userID):
try:
attendance_sheets = AttendanceSheets.query.filter_by(id=userID)
attendance_sheets_dto = [
AttendanceSheetDTO(**attendance_sheet.to_dict())
for attendance_sheet in attendance_sheets
]

attendance_records = AttendanceRecords.query.filter_by(
attendance_sheet_id=userID
)
attendance_records_dto = [
AttendanceRecordsDTO(**attendance_record.to_dict())
for attendance_record in attendance_records
]

return attendance_sheets_dto + attendance_records_dto
except Exception as error:
self.logger.error(str(error))
raise error
7 changes: 6 additions & 1 deletion backend/python/app/services/interfaces/visit_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@


class IVisitService(ABC):
"""
A class to handle CRUD functionality for visits
"""

@abstractmethod
def create_visit(self):
def create_visit(self, intake):
# TODO: Create docstrings
pass
2 changes: 1 addition & 1 deletion backend/python/tools/db_seed.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def insert_test_data():
insert_values(db, "providers", ("name", "file_number", "primary_phone_number", "secondary_phone_number", "email", "address", "relationship_to_child", "additional_contact_notes", "child_id"), value)

# Attendance Sheets
values = [(1, 'Zhang', 'csw', 'cpw', 'fcc'), (2, 2, 'Wang', 'a', 'b', 'c')]
values = [(1, 'Zhang', 'csw', 'cpw', 'fcc'), (2, 'Wang', 'a', 'b', 'c')]
for value in values:
insert_values(db, "attendance_sheets", ("intake_id", "family_name", "csw", "cpw", "fcc"), value)

Expand Down
81 changes: 81 additions & 0 deletions frontend/src/APIClients/VisitAPIClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import baseAPIClient from "./BaseAPIClient";
import AUTHENTICATED_USER_KEY from "../constants/AuthConstants";
import { getLocalStorageObjProperty } from "../utils/LocalStorageUtils";
import { Case } from "../types/CasesContextTypes";

interface Visit {

Check warning on line 6 in frontend/src/APIClients/VisitAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

'Visit' is defined but never used
user_id: number;

Check warning on line 7 in frontend/src/APIClients/VisitAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Delete `··`
case_id: number;

Check warning on line 8 in frontend/src/APIClients/VisitAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Delete `··`
childDetails: {

Check warning on line 9 in frontend/src/APIClients/VisitAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Delete `··`
familyName: string;

Check warning on line 10 in frontend/src/APIClients/VisitAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Replace `········` with `····`
children: string[];

Check warning on line 11 in frontend/src/APIClients/VisitAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Replace `········` with `····`
childServiceWorker: string;

Check warning on line 12 in frontend/src/APIClients/VisitAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Delete `····`
childProtectionWorker: string;

Check warning on line 13 in frontend/src/APIClients/VisitAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Replace `········` with `····`
fosterCareCoordinator: string;

Check warning on line 14 in frontend/src/APIClients/VisitAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Delete `····`
};

Check warning on line 15 in frontend/src/APIClients/VisitAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Delete `··`
visitDetails: {
visitDate: string;
visitDay: string;
visitSupervision: string;
startTime: string;
endTime: string;
location: string;
};
attendanceEntries: {
visitingMembers: string;
visitorRelationship: string;
description: string;
visitingMemberName: string;
visitAttendance: string;
absenceReason: string;
}[];
transportationEntries: {
guardian: string;
name: string;
duration: string;
notes: string;
}[];
}

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
const post = async (formData: any): Promise<Case> => {
const bearerToken = `Bearer ${getLocalStorageObjProperty(
AUTHENTICATED_USER_KEY,
"access_token",
)}`;
try {
const { data } = await baseAPIClient.post("/visits", formData, {
headers: { Authorization: bearerToken },
});
return data;
} catch (error) {
return error;
}
};

const put = async ({
changedData,
intakeID,
}: {
changedData: Record<string, string>;
intakeID: number;
}): Promise<Case> => {
const bearerToken = `Bearer ${getLocalStorageObjProperty(
AUTHENTICATED_USER_KEY,
"access_token",
)}`;
try {
const { data } = await baseAPIClient.put(
`/visit/${intakeID}`,
changedData,
{
headers: { Authorization: bearerToken },
},
);
return data;
} catch (error) {
return error;
}
};

export default { post, put };
5 changes: 5 additions & 0 deletions frontend/src/components/pages/CaseOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ const CaseOverviewBody = (): React.ReactElement => {
history.push("/intake");
};

const goToVisitation = () => {
history.push(`/visit/${caseNumber}`)
}

const goToHomepage = () => {
history.push("/");
};
Expand Down Expand Up @@ -382,6 +386,7 @@ const CaseOverviewBody = (): React.ReactElement => {
right="4"
borderColor={colors.blue[300]}
backgroundColor={colors.blue[100]}
onClick={goToVisitation}
>
<div style={{ paddingRight: "10px" }}>
<UserPlus width="13px" />
Expand Down
Loading
Loading