Skip to content
Merged
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
1 change: 1 addition & 0 deletions auth-api/src/auth_api/exceptions/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class Error(Enum):
)
BCEID_USERS_CANT_BE_OWNERS = "BCEID Users cant be owners", HTTPStatus.BAD_REQUEST
PAYMENT_ACCOUNT_UPSERT_FAILED = "Account upsert failed in Pay", HTTPStatus.INTERNAL_SERVER_ERROR
ACCOUNT_FEES_FETCH_FAILED = "Failed to fetch account fees from Pay API", HTTPStatus.INTERNAL_SERVER_ERROR
GOVM_ACCOUNT_DATA_MISSING = (
"GOVM account creation needs payment info , gl code and mailing address",
HTTPStatus.BAD_REQUEST,
Expand Down
2 changes: 2 additions & 0 deletions auth-api/src/auth_api/models/dataclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ class TaskSearch: # pylint: disable=too-many-instance-attributes
submitted_sort_order: str = "asc"
page: int = 1
limit: int = 10
action: str = ""


@dataclass
Expand All @@ -201,6 +202,7 @@ class ProductReviewTask:

org_id: str
org_name: str
org_access_type: str
product_code: str
product_description: str
product_subscription_id: int
Expand Down
2 changes: 2 additions & 0 deletions auth-api/src/auth_api/models/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ def fetch_tasks(cls, task_search: TaskSearch):
query = query.filter(Task.type == task_search.type)
if task_search.status:
query = query.filter(Task.status.in_(task_search.status))
if task_search.action:
query = query.filter(Task.action.in_(task_search.action))
start_date = None
end_date = None
if task_search.start_date:
Expand Down
1 change: 1 addition & 0 deletions auth-api/src/auth_api/resources/v1/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def get_tasks():
relationship_status=request.args.get("relationshipStatus", None),
type=request.args.get("type", None),
status=request.args.getlist("status", None),
action=request.args.getlist("action", None),
modified_by=request.args.get("modifiedBy", None),
submitted_sort_order=request.args.get("submittedSortOrder", None),
page=int(request.args.get("page", 1)),
Expand Down
16 changes: 8 additions & 8 deletions auth-api/src/auth_api/services/org.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,16 @@ def create_org(org_info: dict, user_id):
# create the membership record for this user if its not created by staff and access_type is anonymous
Org.create_membership(org, user_id)

# Send an email to staff to remind review the pending account
is_staff_review_needed = access_type == AccessType.GOVN.value or (
access_type in (AccessType.EXTRA_PROVINCIAL.value, AccessType.REGULAR_BCEID.value)
and not AffidavitModel.find_approved_by_user_id(user_id=user_id)
and current_app.config.get("SKIP_STAFF_APPROVAL_BCEID") is False
)

if product_subscriptions is not None:
ProductService.create_product_subscription(
org.id, subscription_data={"subscriptions": product_subscriptions}, skip_auth=True
org.id, subscription_data={"subscriptions": product_subscriptions}, skip_auth=True, staff_review_for_create_org=is_staff_review_needed
)

ProductService.create_subscription_from_bcol_profile(org.id, bcol_profile_flags)
Expand All @@ -153,13 +160,6 @@ def create_org(org_info: dict, user_id):
if payment_account_status == PaymentAccountStatus.FAILED and error is not None:
current_app.logger.warning(f"Account update payment Error: {error}")

# Send an email to staff to remind review the pending account
is_staff_review_needed = access_type == AccessType.GOVN.value or (
access_type in (AccessType.EXTRA_PROVINCIAL.value, AccessType.REGULAR_BCEID.value)
and not AffidavitModel.find_approved_by_user_id(user_id=user_id)
and current_app.config.get("SKIP_STAFF_APPROVAL_BCEID") is False
)

if is_staff_review_needed:
Org._create_staff_review_task(org, UserModel.find_by_jwt_token())

Expand Down
92 changes: 71 additions & 21 deletions auth-api/src/auth_api/services/products.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
get_product_notification_data,
get_product_notification_type,
)
from auth_api.utils.roles import CLIENT_ADMIN_ROLES, CLIENT_AUTH_ROLES, STAFF
from auth_api.utils.roles import CLIENT_ADMIN_ROLES, CLIENT_AUTH_ROLES, GOV_ORG_TYPES, STAFF
from auth_api.utils.user_context import UserContext, user_context

from .activity_log_publisher import ActivityLogPublisher
Expand Down Expand Up @@ -156,6 +156,41 @@ def resubmit_product_subscription(org_id, subscription_data: dict[str, Any], ski

return Product.get_all_product_subscription(org_id=org_id, skip_auth=True)

@staticmethod
def _check_gov_org_add_product_previously_approved(
org_id: int,
product_code: str
) -> tuple[bool, Any]:
"""Check if GOV org's account fee product was previously approved (NEW_PRODUCT_FEE_REVIEW task)."""
inactive_sub = ProductSubscriptionModel.find_by_org_id_product_code(
org_id=org_id, product_code=product_code, valid_statuses=(ProductSubscriptionStatus.INACTIVE.value,)
)
if not inactive_sub:
return False, None
task_add_product = TaskModel.find_by_task_relationship_id(
inactive_sub.id, TaskRelationshipType.PRODUCT.value, TaskStatus.COMPLETED.value
)
task_create_org = TaskModel.find_by_task_relationship_id(
org_id, TaskRelationshipType.ORG.value, TaskStatus.COMPLETED.value
)
product_invalid = (
task_add_product is None or (
task_add_product.action in (TaskAction.NEW_PRODUCT_FEE_REVIEW.value, TaskAction.PRODUCT_REVIEW.value)
and task_add_product.relationship_status != TaskRelationshipStatus.ACTIVE.value
)
)
if product_invalid:
org_invalid = (
task_create_org is None or (
task_create_org.action in (TaskAction.AFFIDAVIT_REVIEW.value, TaskAction.ACCOUNT_REVIEW.value)
and task_create_org.relationship_status != TaskRelationshipStatus.ACTIVE.value
)
)

if org_invalid:
return False, None
return True, inactive_sub

@staticmethod
def _is_previously_approved(org_id: int, product_code: str):
"""Check if this product has a task that was previously approved."""
Expand All @@ -170,7 +205,7 @@ def _is_previously_approved(org_id: int, product_code: str):
)
if task is None or (
task.relationship_status != TaskRelationshipStatus.ACTIVE.value
and task.action == TaskAction.PRODUCT_REVIEW.value
and task.action in (TaskAction.PRODUCT_REVIEW.value, TaskAction.NEW_PRODUCT_FEE_REVIEW.value)
):
return False, None

Expand All @@ -183,6 +218,7 @@ def create_product_subscription(
is_new_transaction: bool = True,
skip_auth=False,
auto_approve=False,
staff_review_for_create_org=False,
):
"""Create product subscription for the user.

Expand All @@ -198,6 +234,7 @@ def create_product_subscription(

subscriptions_list = subscription_data.get("subscriptions")
for subscription in subscriptions_list:
auto_approve_current = auto_approve
product_code = subscription.get("productCode")
if ProductSubscriptionModel.find_by_org_id_product_code(org_id, product_code):
raise BusinessException(Error.PRODUCT_SUBSCRIPTION_EXISTS, None)
Expand All @@ -206,11 +243,20 @@ def create_product_subscription(
# Check if product requires system admin, if yes abort
if product_model.need_system_admin:
check_auth(system_required=True, org_id=org_id)
previously_approved, inactive_sub = Product._is_previously_approved(org_id, product_code)

if org.access_type in GOV_ORG_TYPES and not staff_review_for_create_org:
previously_approved, inactive_sub = Product._check_gov_org_add_product_previously_approved(
org.id, product_code
)
else:
previously_approved, inactive_sub = Product._is_previously_approved(org_id, product_code)

if previously_approved:
auto_approve = True
auto_approve_current = True

subscription_status = Product.find_subscription_status(org, product_model, auto_approve)
subscription_status = Product.find_subscription_status(
org, product_model, auto_approve_current, staff_review_for_create_org
)
product_subscription = Product._subscribe_and_publish_activity(
SubscriptionRequest(
org_id=org_id,
Expand Down Expand Up @@ -245,6 +291,7 @@ def create_product_subscription(
ProductReviewTask(
org_id=org.id,
org_name=org.name,
org_access_type=org.access_type,
product_code=product_subscription.product_code,
product_description=product_model.description,
product_subscription_id=product_subscription.id,
Expand Down Expand Up @@ -374,11 +421,14 @@ def _reset_subscription_and_review_task(
@staticmethod
def _create_review_task(review_task: ProductReviewTask):
task_type = review_task.product_description
action_type = (
TaskAction.QUALIFIED_SUPPLIER_REVIEW.value
if review_task.product_code in QUALIFIED_SUPPLIER_PRODUCT_CODES
else TaskAction.PRODUCT_REVIEW.value
)

required_review_types = {AccessType.GOVM.value, AccessType.GOVN.value}
if review_task.product_code in QUALIFIED_SUPPLIER_PRODUCT_CODES:
action_type = TaskAction.QUALIFIED_SUPPLIER_REVIEW.value
elif review_task.org_access_type in required_review_types:
action_type = TaskAction.NEW_PRODUCT_FEE_REVIEW.value
else:
action_type = TaskAction.PRODUCT_REVIEW.value

task_info = {
"name": review_task.org_name,
Expand All @@ -396,14 +446,13 @@ def _create_review_task(review_task: ProductReviewTask):
TaskService.create_task(task_info, False)

@staticmethod
def find_subscription_status(org, product_model, auto_approve=False):
def find_subscription_status(org, product_model, auto_approve=False, staff_review_for_create_org=False):
"""Return the subscriptions status based on org type."""
# GOVM accounts has default active subscriptions
skip_review_types = [AccessType.GOVM.value]
if product_model.need_review and auto_approve is False:
skip_review = org.access_type in GOV_ORG_TYPES and staff_review_for_create_org # prevent create second task when it's already added a staff review when creating org
if (product_model.need_review or org.access_type in GOV_ORG_TYPES) and not auto_approve:
return (
ProductSubscriptionStatus.ACTIVE.value
if (org.access_type in skip_review_types)
if skip_review
else ProductSubscriptionStatus.PENDING_STAFF_REVIEW.value
)
return ProductSubscriptionStatus.ACTIVE.value
Expand Down Expand Up @@ -455,7 +504,10 @@ def get_all_product_subscription(org_id, skip_auth=False, **kwargs):
check_auth(one_of_roles=(*CLIENT_AUTH_ROLES, STAFF), org_id=org_id)

product_subscriptions: list[ProductSubscriptionModel] = ProductSubscriptionModel.find_by_org_ids([org_id])
subscriptions_dict = {x.product_code: x.status_code for x in product_subscriptions}
subscription_by_code = {
sub.product_code: sub
for sub in product_subscriptions
}

# Include hidden products only for staff and SBC staff
include_hidden = (
Expand All @@ -467,9 +519,9 @@ def get_all_product_subscription(org_id, skip_auth=False, **kwargs):

products = Product.get_products(include_hidden=include_hidden, staff_check=False)
for product in products:
product["subscriptionStatus"] = subscriptions_dict.get(
product.get("code"), ProductSubscriptionStatus.NOT_SUBSCRIBED.value
)
sub = subscription_by_code.get(product.get("code"))
product["subscriptionStatus"] = getattr(sub, "status_code", ProductSubscriptionStatus.NOT_SUBSCRIBED.value)
product["id"] = getattr(sub, "id", None)

return products

Expand All @@ -483,7 +535,6 @@ def update_product_subscription(product_sub_info: ProductSubscriptionInfo, is_ne
is_hold = product_sub_info.is_hold
org_id = product_sub_info.org_id
org_name = product_sub_info.org_name

# Approve/Reject Product subscription
product_subscription: ProductSubscriptionModel = ProductSubscriptionModel.find_by_id(product_subscription_id)

Expand All @@ -504,7 +555,6 @@ def update_product_subscription(product_sub_info: ProductSubscriptionInfo, is_ne
product_model: ProductCodeModel = ProductCodeModel.find_by_code(product_subscription.product_code)
# Find admin email addresses
admin_emails = UserService.get_admin_emails_for_org(org_id)

if admin_emails != "" and not is_hold:
Product.send_product_subscription_notification(
ProductNotificationInfo(
Expand Down
1 change: 1 addition & 0 deletions auth-api/src/auth_api/utils/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ class TaskAction(Enum):
ACCOUNT_REVIEW = "ACCOUNT_REVIEW"
PRODUCT_REVIEW = "PRODUCT_REVIEW"
QUALIFIED_SUPPLIER_REVIEW = "QUALIFIED_SUPPLIER_REVIEW"
NEW_PRODUCT_FEE_REVIEW = "NEW_PRODUCT_FEE_REVIEW"


class ActivityAction(Enum):
Expand Down
4 changes: 3 additions & 1 deletion auth-api/src/auth_api/utils/roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from enum import Enum

from .enums import OrgStatus, OrgType, ProductSubscriptionStatus, Status
from .enums import AccessType, OrgStatus, OrgType, ProductSubscriptionStatus, Status


class Role(Enum):
Expand Down Expand Up @@ -87,3 +87,5 @@ class Role(Enum):
EXCLUDED_FIELDS = ("status_code", "type_code")

PREMIUM_ORG_TYPES = (OrgType.PREMIUM.value, OrgType.SBC_STAFF.value, OrgType.STAFF.value)

GOV_ORG_TYPES = (AccessType.GOVM.value, AccessType.GOVN.value)
Loading
Loading