Skip to content

Commit bc8f34d

Browse files
authored
Bug fix - govn add products (bcgov#3606)
1 parent dd9c8e0 commit bc8f34d

File tree

2 files changed

+109
-3
lines changed

2 files changed

+109
-3
lines changed

auth-api/src/auth_api/services/products.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ def create_product_subscription(
199199

200200
subscriptions_list = subscription_data.get("subscriptions")
201201
for subscription in subscriptions_list:
202+
auto_approve_current = auto_approve
202203
product_code = subscription.get("productCode")
203204
if ProductSubscriptionModel.find_by_org_id_product_code(org_id, product_code):
204205
raise BusinessException(Error.PRODUCT_SUBSCRIPTION_EXISTS, None)
@@ -209,10 +210,10 @@ def create_product_subscription(
209210
check_auth(system_required=True, org_id=org_id)
210211
previously_approved, inactive_sub = Product._is_previously_approved(org_id, product_code)
211212
if previously_approved:
212-
auto_approve = True
213+
auto_approve_current = True
213214

214215
subscription_status = Product.find_subscription_status(
215-
org, product_model, auto_approve, staff_review_for_create_org
216+
org, product_model, auto_approve_current, staff_review_for_create_org
216217
)
217218
product_subscription = Product._subscribe_and_publish_activity(
218219
SubscriptionRequest(
@@ -403,7 +404,7 @@ def _create_review_task(review_task: ProductReviewTask):
403404
def find_subscription_status(org, product_model, auto_approve=False, staff_review_for_create_org=False):
404405
"""Return the subscriptions status based on org type."""
405406
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
406-
if product_model.need_review and auto_approve is False:
407+
if (product_model.need_review or org.access_type in GOV_ORG_TYPES) and not auto_approve:
407408
return (
408409
ProductSubscriptionStatus.ACTIVE.value
409410
if skip_review

auth-api/tests/unit/api/test_org.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,111 @@ def test_create_govn_org_with_products_single_staff_review_task(client, jwt, ses
672672
)
673673

674674

675+
def test_govn_org_add_product_pending_staff_review(
676+
client, jwt, session, keycloak_mock, monkeypatch
677+
): # pylint:disable=unused-argument
678+
"""Assert adding a product to a GOVN org via POST /orgs/{id}/products results in PENDING_STAFF_REVIEW."""
679+
patch_pay_account_post(monkeypatch)
680+
headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.public_user_role)
681+
client.post("/api/v1/users", headers=headers, content_type="application/json")
682+
683+
govn_org_payload = {
684+
"name": "test govn add product",
685+
"accessType": AccessType.GOVN.value,
686+
"typeCode": OrgType.PREMIUM.value,
687+
"mailingAddress": TestOrgInfo.get_mailing_address(),
688+
"paymentInfo": {"paymentMethod": PaymentMethod.DIRECT_PAY.value},
689+
}
690+
rv = client.post(
691+
"/api/v1/orgs",
692+
data=json.dumps(govn_org_payload),
693+
headers=headers,
694+
content_type="application/json",
695+
)
696+
assert rv.status_code == HTTPStatus.CREATED
697+
org_id = rv.json["id"]
698+
699+
product_code = ProductCode.BUSINESS_SEARCH.value
700+
rv_products = client.post(
701+
f"/api/v1/orgs/{org_id}/products",
702+
data=json.dumps({"subscriptions": [{"productCode": product_code}]}),
703+
headers=headers,
704+
content_type="application/json",
705+
)
706+
assert rv_products.status_code == HTTPStatus.CREATED
707+
subscriptions = rv_products.json.get("subscriptions", [])
708+
product = next((p for p in subscriptions if p.get("code") == product_code), None)
709+
assert product is not None, f"Product {product_code} should appear in response"
710+
assert product["subscriptionStatus"] == ProductSubscriptionStatus.PENDING_STAFF_REVIEW.value, (
711+
"GOVN org adding product should require staff review"
712+
)
713+
714+
715+
@pytest.mark.parametrize(
716+
"product_code,expected_status,use_factory_org,claims_attr,assert_no_product_task",
717+
[
718+
(ProductCode.NDS.value, ProductSubscriptionStatus.ACTIVE.value, True, "system_role", True),
719+
(ProductCode.VS.value, ProductSubscriptionStatus.PENDING_STAFF_REVIEW.value, False, "public_user_role", False),
720+
],
721+
)
722+
def test_post_org_products_skip_auth_system_vs_org_admin(
723+
client, jwt, session, keycloak_mock, monkeypatch,
724+
product_code, expected_status, use_factory_org, claims_attr, assert_no_product_task,
725+
): # pylint:disable=unused-argument
726+
"""Assert POST /orgs/{id}/products: SYSTEM vs org admin (non-GOVN/GOVM); focus on PENDING_STAFF_REVIEW for org admin."""
727+
headers = factory_auth_header(jwt=jwt, claims=getattr(TestJwtClaims, claims_attr))
728+
729+
if use_factory_org:
730+
regular_org = factory_org_model(org_info={"name": "regular org for system", "accessType": AccessType.REGULAR.value})
731+
org_id = regular_org.id
732+
else:
733+
patch_pay_account_post(monkeypatch)
734+
client.post("/api/v1/users", headers=headers, content_type="application/json")
735+
rv = client.post(
736+
"/api/v1/orgs",
737+
data=json.dumps({
738+
"name": "regular org for org admin",
739+
"accessType": AccessType.REGULAR.value,
740+
"typeCode": OrgType.PREMIUM.value,
741+
"mailingAddress": TestOrgInfo.get_mailing_address(),
742+
"paymentInfo": {"paymentMethod": PaymentMethod.DIRECT_PAY.value},
743+
}),
744+
headers=headers,
745+
content_type="application/json",
746+
)
747+
assert rv.status_code == HTTPStatus.CREATED
748+
org_id = rv.json["id"]
749+
750+
rv_products = client.post(
751+
f"/api/v1/orgs/{org_id}/products",
752+
data=json.dumps({"subscriptions": [{"productCode": product_code}]}),
753+
headers=headers,
754+
content_type="application/json",
755+
)
756+
assert rv_products.status_code == HTTPStatus.CREATED
757+
subs = rv_products.json.get("subscriptions", [])
758+
product = next((p for p in subs if p.get("code") == product_code), None)
759+
if assert_no_product_task:
760+
# NDS is hidden: POST response may not include it; use GET ?include_hidden=true to verify (as in prod workflow)
761+
get_headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.staff_view_accounts_role)
762+
rv_get = client.get(
763+
f"/api/v1/orgs/{org_id}/products?include_hidden=true",
764+
headers=get_headers,
765+
)
766+
assert rv_get.status_code == HTTPStatus.OK
767+
subs = json.loads(rv_get.data)
768+
product = next((p for p in subs if p.get("code") == product_code), None)
769+
assert product is not None
770+
assert product["subscriptionStatus"] == expected_status
771+
772+
if assert_no_product_task:
773+
product_tasks = [
774+
t for t in TaskService.fetch_tasks(TaskSearch(status=[TaskStatus.OPEN.value], page=1, limit=100))["tasks"]
775+
if t.get("relationship_type") == TaskRelationshipType.PRODUCT.value and t.get("account_id") == org_id
776+
]
777+
assert len(product_tasks) == 0, "SYSTEM adding product should not create a product review task"
778+
779+
675780
def test_add_org_invalid_returns_400(client, jwt, session): # pylint:disable=unused-argument
676781
"""Assert that POSTing an invalid org returns a 400."""
677782
headers = factory_auth_header(jwt, claims=TestJwtClaims.public_user_role)

0 commit comments

Comments
 (0)