Skip to content

Commit

Permalink
API changes related to payment and certificate generation (#205)
Browse files Browse the repository at this point in the history
* feat: Payment Service Changes

* Block Certificate generation for platform registrations

* no message
  • Loading branch information
kris-daxiom authored Oct 22, 2024
1 parent 1117775 commit b496dd5
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 25 deletions.
5 changes: 4 additions & 1 deletion strr-api/src/strr_api/enums/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class Role(Enum):

STRR_EXAMINER = "strr_examiner"
STRR_INVESTIGATOR = "strr_investigator"
STRR_AUTOMATION_TESTER = "strr_automation_tester"


class RegistrationStatus(Enum):
Expand Down Expand Up @@ -138,12 +139,14 @@ class RegistrationType(Enum):
class ErrorMessage(Enum):
"""STRR Error Messages."""

APPLICATION_NOT_FOUND = "Application not found"
APPLICATION_NOT_FOUND = "Application not found."
INVALID_APPLICATION_STATUS = "Invalid application status."
APPLICATION_TERMINAL_STATE = "Application has reached the final state."
PROCESSING_ERROR = "An error occurred while processing the request."
DOCUMENT_NOT_FOUND = "Document not found."
APPLICATION_NOT_PAID = "Application does not have a payment record."
REGISTRATION_NOT_FOUND = "Application not found."
PLATFORM_ISSUE_CERTIFICATE_ERROR = "Certificate is not available for a platform registration."


class ApplicationRole(Enum):
Expand Down
11 changes: 7 additions & 4 deletions strr-api/src/strr_api/resources/registrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
from flask_cors import cross_origin

from strr_api.common.auth import jwt
from strr_api.enums.enum import Role
from strr_api.enums.enum import ErrorMessage, RegistrationType, Role
from strr_api.exceptions import AuthException, ExternalServiceException, error_response, exception_response
from strr_api.models import User
from strr_api.responses import Events
Expand Down Expand Up @@ -270,9 +270,12 @@ def issue_registration_certificate(registration_id):
try:
registration = RegistrationService.get_registration(g.jwt_oidc_token_info, registration_id)
if not registration:
return error_response(HTTPStatus.NOT_FOUND, "Registration not found")

# TODO: Throw error if a certificate has been issued already; replace messages with enums
return error_response(HTTPStatus.NOT_FOUND, ErrorMessage.REGISTRATION_NOT_FOUND.value)
if registration.registration_type == RegistrationType.PLATFORM.value:
return error_response(
message=ErrorMessage.PLATFORM_ISSUE_CERTIFICATE_ERROR.value,
http_status=HTTPStatus.BAD_REQUEST,
)

RegistrationService.generate_registration_certificate(registration)
return RegistrationService.serialize(registration), HTTPStatus.CREATED
Expand Down
6 changes: 5 additions & 1 deletion strr-api/src/strr_api/services/application_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,11 @@ def update_application_payment_details_and_status(application: Application, invo
else:
if application.payment_status_code == PaymentStatus.COMPLETED.value:
application.status = Application.Status.PAID
application.payment_completion_date = datetime.fromisoformat(invoice_details.get("paymentDate"))
application.payment_completion_date = (
datetime.fromisoformat(invoice_details.get("paymentDate"))
if invoice_details.get("paymentDate")
else datetime.utcnow()
)
elif application.payment_status_code == PaymentStatus.APPROVED.value:
application.payment_status_code = PaymentStatus.COMPLETED.value
application.status = Application.Status.PAID
Expand Down
46 changes: 28 additions & 18 deletions strr-api/src/strr_api/services/payment_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@
from strr_api.exceptions import ExternalServiceException
from strr_api.models import Application, Events
from strr_api.services.events_service import EventsService
from strr_api.services.user_service import UserService

PLATFORM_SMALL_USER_BASE = "PLATREG_SM"

PLATFORM_LARGE_USER_BASE = "PLATREG_LG"

PLATFORM_FEE_WAIVED = "PLATREG_WV"


class PayService:
Expand All @@ -68,19 +75,7 @@ def init_app(self, app: Flask):
def create_invoice(self, user_jwt: JwtManager, account_id, application=None):
"""Create the invoice via the pay-api."""
application_json = application.application_json
filing_type = self._get_filing_type(application_json)
filing_type_dict = {"filingTypeCode": filing_type}

# Workaround to charge the service fee when the filing fee is 0.
if filing_type == "PLATREG_WV":
filing_type_dict["fee"] = 0

payload = {
"filingInfo": {"filingTypes": [filing_type_dict]},
"businessInfo": {"corpType": "STRR"},
"paymentInfo": {"methodOfPayment": "DIRECT_PAY"},
}

payload = self._get_payment_request(application_json)
try:
token = user_jwt.get_token_auth_header()
headers = {
Expand Down Expand Up @@ -113,7 +108,7 @@ def create_invoice(self, user_jwt: JwtManager, account_id, application=None):
self.app.logger.debug("Pay-api integration (create invoice) failure:", repr(err))
raise ExternalServiceException(error=repr(err), status_code=HTTPStatus.PAYMENT_REQUIRED) from err

def _get_filing_type(self, application_json):
def _get_payment_request(self, application_json):
filing_type = None
registration_json = application_json.get("registration", {})
registration_type = registration_json.get("registrationType")
Expand All @@ -122,12 +117,27 @@ def _get_filing_type(self, application_json):
if registration_type == RegistrationType.PLATFORM.value:
cpbc_number = registration_json.get("businessDetails").get("consumerProtectionBCLicenceNumber")
if cpbc_number and (not cpbc_number.isspace()):
filing_type = "PLATREG_WV"
filing_type = PLATFORM_FEE_WAIVED
elif registration_json.get("platformDetails").get("listingSize") == "GREATER_THAN_THOUSAND":
filing_type = "PLATREG_LG"
filing_type = PLATFORM_LARGE_USER_BASE
else:
filing_type = "PLATREG_SM"
return filing_type
filing_type = PLATFORM_SMALL_USER_BASE

filing_type_dict = {"filingTypeCode": filing_type}

# Workaround to charge the service fee when the filing fee is 0.
if filing_type == PLATFORM_FEE_WAIVED:
filing_type_dict["fee"] = 0

payload = {"filingInfo": {"filingTypes": [filing_type_dict]}, "businessInfo": {"corpType": "STRR"}}

if registration_type == RegistrationType.HOST.value:
payload["paymentInfo"] = {"methodOfPayment": "DIRECT_PAY"}

if UserService.is_automation_tester():
payload["skipPayment"] = True

return payload

def get_payment_details_by_invoice_id(self, user_jwt: JwtManager, account_id, invoice_id: int):
"""Get payment details by invoice id."""
Expand Down
9 changes: 9 additions & 0 deletions strr-api/src/strr_api/services/user_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,12 @@ def get_or_create_user_in_context(cls, **kwargs) -> User:
usr_context: UserContext = kwargs["user_context"]
user = UserService.get_or_create_user_by_jwt(usr_context.token_info)
return user

@classmethod
@user_context
def is_automation_tester(cls, **kwargs) -> bool:
"""Method to check whether the user has automation tester role."""
usr_context: UserContext = kwargs["user_context"]
if usr_context.is_automation_tester():
return True
return False
4 changes: 4 additions & 0 deletions strr-api/src/strr_api/utils/user_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ def is_investigator(self) -> bool:
"""Return True if the user is staff user with strr_investigator role."""
return Role.STRR_INVESTIGATOR.value in self._roles if self._roles else False

def is_automation_tester(self) -> bool:
"""Return True if the user has strr_automation_tester role."""
return Role.STRR_AUTOMATION_TESTER.value in self._roles if self._roles else False

@property
def name(self) -> str:
"""Return the name."""
Expand Down
30 changes: 29 additions & 1 deletion strr-api/tests/unit/resources/test_registrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def test_get_registration_events(session, client, jwt):


@patch("strr_api.services.strr_pay.create_invoice", return_value=MOCK_INVOICE_RESPONSE)
def test_issue_certificate_examiner(session, client, jwt):
def test_examiner_issue_certificate_for_host_registration(session, client, jwt):
with open(CREATE_HOST_REGISTRATION_REQUEST) as f:
headers = create_header(jwt, [PUBLIC_USER], "Account-Id")
headers["Account-Id"] = ACCOUNT_ID
Expand Down Expand Up @@ -185,6 +185,34 @@ def test_issue_certificate_examiner(session, client, jwt):
assert response_json.get("header").get("hostActions") == []


@patch("strr_api.services.strr_pay.create_invoice", return_value=MOCK_INVOICE_RESPONSE)
def test_examiner_issue_certificate_for_platform_registration(session, client, jwt):
with open(CREATE_PLATFORM_REGISTRATION_REQUEST) as f:
headers = create_header(jwt, [PUBLIC_USER], "Account-Id")
headers["Account-Id"] = ACCOUNT_ID
json_data = json.load(f)
rv = client.post("/applications", json=json_data, headers=headers)
response_json = rv.json
application_number = response_json.get("header").get("applicationNumber")

application = Application.find_by_application_number(application_number=application_number)
application.payment_status = PaymentStatus.COMPLETED.value
application.save()

staff_headers = create_header(jwt, [STRR_EXAMINER], "Account-Id")
status_update_request = {"status": Application.Status.FULL_REVIEW_APPROVED}
rv = client.put(f"/applications/{application_number}/status", json=status_update_request, headers=staff_headers)
assert HTTPStatus.OK == rv.status_code
response_json = rv.json
assert response_json.get("header").get("status") == Application.Status.FULL_REVIEW_APPROVED
assert response_json.get("header").get("reviewer").get("username") is not None
assert response_json.get("header").get("registrationId") is not None
assert response_json.get("header").get("registrationNumber") is not None
registration_id = response_json.get("header").get("registrationId")
rv = client.post(f"/registrations/{registration_id}/certificate", headers=staff_headers)
assert rv.status_code == HTTPStatus.BAD_REQUEST


@patch("strr_api.services.strr_pay.create_invoice", return_value=MOCK_INVOICE_RESPONSE)
def test_issue_certificate_public_user(session, client, jwt):
with open(CREATE_HOST_REGISTRATION_REQUEST) as f:
Expand Down

0 comments on commit b496dd5

Please sign in to comment.