Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions backend/python/app/models/child.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from . import db
from .base_mixin import BaseMixin
from .child_providers import child_providers
from .children_child_behaviors import children_child_behaviors


Expand All @@ -20,6 +21,9 @@ class Child(db.Model, BaseMixin):
intake = db.relationship("Intake")
daytime_contact = db.relationship("DaytimeContact")
behaviors = db.relationship("ChildBehavior", secondary=children_child_behaviors)
providers = db.relationship(
"Provider", backref="children", secondary=child_providers
)
visit_cadences = db.relationship(
"VisitCadence", backref="associated_child", cascade="all, delete"
)
8 changes: 8 additions & 0 deletions backend/python/app/models/child_providers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from . import db

child_providers = db.Table(
"child_providers",
db.metadata,
db.Column("child_id", db.ForeignKey("children.id")),
db.Column("providers_id", db.ForeignKey("providers.id")),
)
3 changes: 1 addition & 2 deletions backend/python/app/models/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Provider(db.Model, BaseMixin):
__tablename__ = "providers"

id = db.Column(db.Integer, primary_key=True)
intake_id = db.Column(db.Integer, db.ForeignKey("intakes.id"), nullable=True)
name = db.Column(db.String, nullable=False)
file_number = db.Column(db.String, nullable=False)
primary_phone_number = db.Column(db.String, nullable=False)
Expand All @@ -14,5 +15,3 @@ class Provider(db.Model, BaseMixin):
address = db.Column(db.String, nullable=False)
relationship_to_child = db.Column(db.String, nullable=False)
additional_contact_notes = db.Column(db.String, nullable=True)
child_id = db.Column(db.Integer, db.ForeignKey("children.id"), nullable=False)
child = db.relationship("Child", backref="providers")
4 changes: 1 addition & 3 deletions backend/python/app/resources/provider_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class ProviderDTO:
def __init__(self, **kwargs):
self.id = kwargs.get("id")
self.intake_id = kwargs.get("intake_id")
self.name = kwargs.get("name")
self.file_number = kwargs.get("file_number")
self.primary_phone_number = kwargs.get("primary_phone_number")
Expand All @@ -12,7 +13,6 @@ def __init__(self, **kwargs):
self.address = kwargs.get("address")
self.relationship_to_child = kwargs.get("relationship_to_child")
self.additional_contact_notes = kwargs.get("additional_contact_notes")
self.child_id = kwargs.get("child_id")


class CreateProviderDTO(ProviderDTO):
Expand All @@ -34,8 +34,6 @@ def validate(self):
or not type(self.relationship_to_child) == str
):
error_list.append("The relationship to child supplied is invalid")
if not self.child_id or not type(self.child_id) == int:
error_list.append("The child id supplied is invalid")

# optional fields
if self.secondary_phone_number and not type(self.secondary_phone_number) == str:
Expand Down
61 changes: 37 additions & 24 deletions backend/python/app/rest/intake_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def get_all_intakes():
just_children = child_service.get_children_by_intake_id(intake.id)
new_children = []
for child in just_children:
providers = provider_service.get_providers_by_child_id(child.id)
providers = provider_service.get_providers_by_child(child.id)
child_info = {
"name": f"{child.first_name} {child.last_name}",
"dateOfBirth": child.date_of_birth,
Expand Down Expand Up @@ -325,7 +325,10 @@ def run_undos():
run_undos()
return jsonify(error), 400

children_providers = {}
all_providers = []
children = request.json["children"]
# children
for child in children:
# daytime contact
daytimeContact = child["daytimeContact"]
Expand Down Expand Up @@ -369,29 +372,15 @@ def run_undos():
return jsonify(error), 400

# provider
providers = child["provider"]
for provider in providers:
provider_obj = {
"name": provider["name"],
"file_number": provider["fileNumber"],
"primary_phone_number": provider["primaryPhoneNumber"],
"secondary_phone_number": provider["secondaryPhoneNumber"],
"email": provider["email"],
"address": provider["address"],
"relationship_to_child": provider["relationshipToChild"],
"additional_contact_notes": provider["additionalContactNotes"],
"child_id": child_response.id,
}
try:
provider_response = provider_service.create_new_provider(
CreateProviderDTO(**provider_obj)
)
undos.append(
(provider_service, "delete_provider", provider_response.id)
)
except Exception as error:
run_undos()
return jsonify(error), 400
providers_by_child = child["provider"]
for provider in providers_by_child:
if provider.providerId in children_providers:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i c wat ur going for here, but when the user POSTs the intake obj, the provider obj within it has no field providerId (see intake frontend<>backend for more info)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While working on the changes, I added a providerId which is now included in the provider interface apart of ProviderDetails, so it should work. It's present in this file: .\frontend\src\components\intake\NewProviderModal.tsx and is defined across all components working with ProviderDetails

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

provider["providerId"]

children_providers[provider["providerId"]].append(child_response.id)
else:
children_providers[provider["providerId"]] = [child_response.id]

if not any(x.providerId == provider.providerId for x in all_providers):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

provider["providerId"]

all_providers.append(provider)

# concerns
concerns = child["childInfo"]["concerns"]
Expand All @@ -415,6 +404,30 @@ def run_undos():
run_undos()
return jsonify(error), 400

# create providers
for provider in all_providers:
provider_obj = {
"name": provider["name"],
"intake_id": new_intake.id,
"file_number": provider["fileNumber"],
"primary_phone_number": provider["primaryPhoneNumber"],
"secondary_phone_number": provider["secondaryPhoneNumber"],
"email": provider["email"],
"address": provider["address"],
"relationship_to_child": provider["relationshipToChild"],
"additional_contact_notes": provider["additionalContactNotes"],
}

try:
provider_response = provider_service.create_new_provider(
CreateProviderDTO(**provider_obj),
children_providers[provider["providerId"]],
Comment on lines +422 to +424
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, just looked into this—it seems like the create_new_provider function doesn't work when it takes in children_ids as a param..
for now (until we fix this), keep the arg for create_new_provider as

provider_response = provider_service.create_new_provider(
    CreateProviderDTO(**provider_obj)
)

you're going to have to change some of your providers_by_child logic, since atm the POST request doesn't save providers properly

)
undos.append((provider_service, "delete_provider", provider_response.id))
except Exception as error:
run_undos()
return jsonify(error), 400

Check warning

Code scanning / CodeQL

Information exposure through an exception

[Stack trace information](1) flows to this location and may be exposed to an external user.

return jsonify(new_intake.__dict__), 201


Expand Down
10 changes: 10 additions & 0 deletions backend/python/app/services/implementations/child_service.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from ...models import db
from ...models.child import Child
from ...models.provider import Provider
from ...resources.child_dto import ChildDTO, CreateChildDTO
from ..interfaces.child_service import IChildService

Expand Down Expand Up @@ -59,3 +60,12 @@ def get_children_by_intake_id(self, intake_id):
except Exception as error:
self.logger.error(str(error))
raise error

def get_children_by_provider(self, provider_id):
try:
provider = Provider.query.filter_by(id=provider_id).first()
children_dto = [ChildDTO(**child.to_dict()) for child in provider.children]
return children_dto
except Exception as error:
self.logger.error(str(error))
raise error
18 changes: 12 additions & 6 deletions backend/python/app/services/implementations/provider_service.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from ...models import db
from ...models.child import Child
from ...models.provider import Provider
from ...resources.child_dto import ChildDTO
from ...resources.provider_dto import CreateProviderDTO, ProviderDTO
from ..interfaces.provider_service import IProviderService

Expand All @@ -20,7 +21,7 @@ def get_all_providers(self):
self.logger.error(str(error))
raise error

def create_new_provider(self, provider):
def create_new_provider(self, provider, children_ids=[]):
try:
if not provider:
raise Exception(
Expand All @@ -33,6 +34,11 @@ def create_new_provider(self, provider):
raise Exception(error_list)

new_provider_entry = Provider(**provider.__dict__)

for child_id in children_ids:
child = Child.query.filter_by(id=child_id)
new_provider_entry.children.append(child)

db.session.add(new_provider_entry)
db.session.commit()

Expand All @@ -53,13 +59,13 @@ def delete_provider(self, provider_id):
db.session.rollback()
raise error

def get_providers_by_child_id(self, child_id):
def get_providers_by_child(self, child_id):
try:
providers = Provider.query.filter_by(child_id=child_id)
providers_dto = [
ProviderDTO(**provider.to_dict()) for provider in providers
child = Child.query.filter_by(id=child_id).first()
provider_dto = [
ProviderDTO(**provider.to_dict()) for provider in child.providers
]
return providers_dto
return provider_dto
except Exception as error:
self.logger.error(str(error))
raise error
11 changes: 11 additions & 0 deletions backend/python/app/services/interfaces/child_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,14 @@ def get_children_by_intake_id(self, intake_id):
:raises Exception: if an error occurs in the database layer
"""
pass

@abstractmethod
def get_children_by_provider(self, id):
"""Returns all children associated with a provider's ID
:param id: the ID of the provider
:type id: int
:return: list of ChildDTO
:rtype: list of ChildDTO
:raises Exception: if an error occurs at the database level
"""
pass
2 changes: 1 addition & 1 deletion backend/python/app/services/interfaces/provider_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def delete_provider(self, provider_id):
pass

@abstractmethod
def get_providers_by_child_id(self, child_id):
def get_providers_by_child(self, child_id):
"""Returns all providers associated with a child's ID
:param child_id: the ID of the child
:type child_id: int
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Change child provider relationship

Revision ID: 142c528373ea
Revises: db7c2f31d3ea
Create Date: 2023-12-05 00:58:54.363918

"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "142c528373ea"
down_revision = "db7c2f31d3ea"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"child_providers",
sa.Column("child_id", sa.Integer(), nullable=True),
sa.Column("providers_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(
["child_id"],
["children.id"],
),
sa.ForeignKeyConstraint(
["providers_id"],
["providers.id"],
),
)
op.add_column("providers", sa.Column("intake_id", sa.Integer(), nullable=True))
op.drop_constraint("providers_child_id_fkey", "providers", type_="foreignkey")
op.create_foreign_key(None, "providers", "intakes", ["intake_id"], ["id"])
op.drop_column("providers", "child_id")
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
"providers",
sa.Column("child_id", sa.INTEGER(), autoincrement=False, nullable=False),
)
op.drop_constraint(None, "providers", type_="foreignkey")
op.create_foreign_key(
"providers_child_id_fkey", "providers", "children", ["child_id"], ["id"]
)
op.drop_column("providers", "intake_id")
op.drop_table("child_providers")
# ### end Alembic commands ###
3 changes: 0 additions & 3 deletions backend/python/tests/functional/test_provider_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
"secondary_phone_number": "1234567890",
"address": "123 Main St",
"relationship_to_child": "Mother",
"child_id": 1,
}


Expand Down Expand Up @@ -91,7 +90,6 @@ def test_create_new_provider_valid(provider_service):
secondary_phone_number="0987654321",
address="321 Main St",
relationship_to_child="Father",
child_id=1,
)

provider_instance = provider_service.create_new_provider(param)
Expand All @@ -113,7 +111,6 @@ def test_invalid_arg(provider_service):
secondary_phone_number="0987654321",
address="321 Main St",
relationship_to_child="Father",
child_id=1,
)
with pytest.raises(Exception):
provider_service.create_new_provider(param)
Expand Down
11 changes: 4 additions & 7 deletions backend/python/tools/db_seed.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,11 @@ def insert_test_data():
insert_values(db, "other_permitted_individuals", ("name", "phone_number", "relationship_to_child", "notes", "intake_id"), value)


# Providers
values = [
('Provider One', '111', '555-555-5555', '777-777-7777', '[email protected]', 'address', 'KINSHIP_PROVIDER', 'NULL', 1),
('Provider Two', '222', '777-777-7777', '555-555-5555', '[email protected]', 'address', 'KINSHIP_PROVIDER', 'NULL', 1)
]
# Providers
values = [(1, "Karen Namen", "123123", "primary phone", "secondary phone", "[email protected]", "address", "FOSTER CAREGIVER")]

for value in values:
insert_values(db, "providers", ("name", "file_number", "primary_phone_number", "secondary_phone_number", "email", "address", "relationship_to_child", "additional_contact_notes", "child_id"), value)
insert_values(db, "providers", ("intake_id", "name", "file_number", "primary_phone_number", "secondary_phone_number", "email", "address", "relationship_to_child", "additional_contact_notes"), value)


values_sheets = [(999, 'Zhang' , 'csw', 'cpw', 'fcc'),
Expand All @@ -131,7 +128,7 @@ def insert_test_data():
values_records = [
(999, 999, 'FULL', '2023-01-01', '08:00:00', '17:00:00', 'Location Value', 'PRESENT', 'MOM', 30, 15, 10, 1, 'Comments Value'),
(1000, 1000, 'PARTIAL', '2023-01-02', '09:00:00', '18:00:00', 'Location Value', 'NO_SHOW', 'DAD', 45, 20, 12, 2, 'Comments Value'),
]
]

for value in values_records:
insert_values(db, "attendance_records", ("id", "attendance_sheet_id", "supervision", "date", "start_time", "end_time", "location", "attendance", "attending_family", "staff_transport_time_min", "driver_transport_time_min", "foster_parent_transport_time_min", "child_family_support_worker_id", "comments"), value)
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/components/intake/NewProviderModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type ProviderDetails = {
contactNotes?: string;
address: string;
relationship: string;
providerId: number;
};

export type Providers = ProviderDetails[];
Expand All @@ -23,13 +24,15 @@ type NewProviderProps = {
onClick: (newProvider: ProviderDetails) => void;
onClose: () => void;
provider: ProviderDetails;
providerId: number;
};

const NewProviderModal = ({
isOpen,
onClick,
onClose,
provider,
providerId,
}: NewProviderProps): React.ReactElement => {
const [providerName, setProviderName] = useState("");
const [providerFileNo, setProviderFileNo] = useState("");
Expand Down Expand Up @@ -234,6 +237,7 @@ const NewProviderModal = ({
relationship: relationshipChanged
? relationship
: provider.relationship,
providerId,
};
onClick(newProvider);
handleClose();
Expand Down
Loading