Skip to content

Commit

Permalink
Merge pull request #445 from open-contracting/425-lapse-application
Browse files Browse the repository at this point in the history
feat: add lapse application endpoint
  • Loading branch information
yolile authored Dec 3, 2024
2 parents 9e8cfc8 + de47d21 commit eaca0f0
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 7 deletions.
6 changes: 4 additions & 2 deletions app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,9 @@ class ApplicationStatus(StrEnum):
#:
#: (``/applications/email-sme/{id}``)
INFORMATION_REQUESTED = i("INFORMATION_REQUESTED")
#: Borrower doesn't accept or decline the invitation, doesn't submit the application or information requested, or
#: doesn't start external onboarding while the lender hasn't started application review.
#: Borrower doesn't accept or decline the invitation, doesn't submit the application or information requested,
#: doesn't start external onboarding while the lender hasn't started application review, or doesn't respond to
#: the lender externally.
#:
#: (:typer:`python-m-app-update-applications-to-lapsed`)
LAPSED = i("LAPSED")
Expand Down Expand Up @@ -267,6 +268,7 @@ class ApplicationActionType(StrEnum):
OCP_DOWNLOAD_APPLICATION = "OCP_DOWNLOAD_APPLICATION"
FI_START_APPLICATION = "FI_START_APPLICATION"
FI_REQUEST_INFORMATION = "FI_REQUEST_INFORMATION"
FI_LAPSE_APPLICATION = "FI_LAPSE_APPLICATION"
OCP_DOWNLOAD_DOCUMENT = "OCP_DOWNLOAD_DOCUMENT"
APPROVED_APPLICATION = "APPROVED_APPLICATION"
REJECTED_APPLICATION = "REJECTED_APPLICATION"
Expand Down
39 changes: 39 additions & 0 deletions app/routers/applications.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,3 +528,42 @@ async def previous_contracts(
:raise: HTTPException if the user is not authorized to access the application.
"""
return application.previous_awards(session)


@router.post(
"/applications/{id}/lapse",
tags=[util.Tags.applications],
response_model=models.ApplicationWithRelations,
)
async def lapse_application(
id: int,
user: Annotated[models.User, Depends(dependencies.get_user)],
session: Annotated[Session, Depends(get_db)],
application: Annotated[
models.Application,
Depends(
dependencies.get_scoped_application_as_user(
roles=(models.UserType.FI,), statuses=(models.ApplicationStatus.STARTED,)
)
),
],
) -> Any:
"""
:param id: The ID of the application to lapse.
:return: The lapsed application with its associated relations.
:raise: HTTPException if the user is not authorized to lapse the application.
"""
with rollback_on_error(session):
application.status = models.ApplicationStatus.LAPSED
application.application_lapsed_at = datetime.now(application.created_at.tzinfo)

models.ApplicationAction.create(
session,
type=models.ApplicationActionType.FI_LAPSE_APPLICATION,
data=jsonable_encoder(application, exclude_unset=True),
application_id=application.id,
user_id=user.id,
)

session.commit()
return application
2 changes: 1 addition & 1 deletion docs/_static/openapi.json

Large diffs are not rendered by default.

Binary file modified docs/_static/orphans.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/relationships.real.large.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/state-machine.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 5 additions & 4 deletions docs/contributing/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -268,17 +268,18 @@ Application status transitions
https://play.d2lang.com
https://pincel.app/tools/svg-to-png
α -> PENDING: Credere sends an invitation to the borrower
PENDING -> LAPSED: borrower doesn't accept or decline the invitation
PENDING -> LAPSED: borrower doesn't\naccept or decline the invitation
PENDING -> DECLINED: borrower declines the invitation
PENDING -> ACCEPTED: borrower accepts the invitation
ACCEPTED -> LAPSED: borrower doesn't submit the application
ACCEPTED -> LAPSED: borrower doesn't\nsubmit the application
ACCEPTED -> SUBMITTED: borrower submits the application
SUBMITTED -> LAPSED: borrower doesn't start external onboarding {class: external}
SUBMITTED -> LAPSED: borrower doesn't\nstart external onboarding {class: external}
SUBMITTED -> STARTED: lender starts application review
STARTED -> INFORMATION_REQUESTED: lender requests\nthe borrower to update a document {class: native}
STARTED -> REJECTED: lender rejects the application
STARTED -> APPROVED: lender approves the application
INFORMATION_REQUESTED -> LAPSED: borrower doesn't submit the information requested {class: native}
STARTED -> LAPSED: lender lapses the application if the borrower\nis unresponsive to external messages
INFORMATION_REQUESTED -> LAPSED: borrower doesn't\nsubmit the information requested {class: native}
INFORMATION_REQUESTED -> STARTED: borrower updates the document {class: native}
classes: {
native.style.stroke: maroon
Expand Down
29 changes: 29 additions & 0 deletions migrations/versions/f4f2b2a76181_add_new_action_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""
add new action type
Revision ID: f4f2b2a76181
Revises: 867ef39e878c
Create Date: 2024-11-28 11:55:31.469382
"""

from alembic import op

# revision identifiers, used by Alembic.
revision = "f4f2b2a76181"
down_revision = "867ef39e878c"
branch_labels = None
depends_on = None


def upgrade() -> None:
with op.get_context().autocommit_block():
op.execute(
"""
ALTER TYPE application_action_type ADD VALUE IF NOT EXISTS 'FI_LAPSE_APPLICATION'
"""
)


def downgrade() -> None:
pass
13 changes: 13 additions & 0 deletions tests/routers/test_applications.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,16 @@ def test_get_applications(client, session, admin_header, lender_header, pending_
response = client.post("/applications/access-scheme", json={"uuid": "123-456"})
assert response.status_code == status.HTTP_404_NOT_FOUND
assert response.json() == {"detail": _("Application not found")}


def test_lapse_application(client, session, lender_header, pending_application):
response = client.post(f"/applications/{pending_application.id}/lapse", headers=lender_header)
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
assert response.json() == {"detail": _("Application status should not be %(status)s", status=_("PENDING"))}

pending_application.status = models.ApplicationStatus.STARTED
session.commit()

response = client.post(f"/applications/{pending_application.id}/lapse", headers=lender_header)
assert_ok(response)
assert response.json()["status"] == models.ApplicationStatus.LAPSED

0 comments on commit eaca0f0

Please sign in to comment.