diff --git a/CHANGELOG.md b/CHANGELOG.md
index a2e67273b..b43835e86 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## 2025-03-10
+- [PI-387] Add Product Team Id to search results
+- [PI-843] Add Read Product to test UI
+- [PI-764] Refine Swagger
+
## 2025-03-07
- [PI-383] External ID
- [PI-838] product_team includes product_team_id
diff --git a/VERSION b/VERSION
index 82166197a..a7d6d5f25 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2025.03.07
+2025.03.10
diff --git a/changelog/2025-03-10.md b/changelog/2025-03-10.md
new file mode 100644
index 000000000..48f663f64
--- /dev/null
+++ b/changelog/2025-03-10.md
@@ -0,0 +1,3 @@
+- [PI-387] Add Product Team Id to search results
+- [PI-843] Add Read Product to test UI
+- [PI-764] Refine Swagger
diff --git a/infrastructure/swagger/02_info.yaml b/infrastructure/swagger/02_info.yaml
index 974708506..260ff1c99 100644
--- a/infrastructure/swagger/02_info.yaml
+++ b/infrastructure/swagger/02_info.yaml
@@ -12,23 +12,32 @@ info:
description: |
## Overview
- API to configure internal systems to allow a Connecting Party to connect. A source of information about Connecting Parties (systems that connect to NHSE) that helps provide system identity attributes that ensure NHSE services know what systems they are connecting to and the legal entities they are sharing data with. This service is driven by APIs that enable self-service for activities such as certificate management and environment access. It also is a store of end-to-end onboarding/integration data and a catalogue of endpoints.
+ Use this API to access the Connecting Party Manager (CPM) service - an internal service for the creation and management of product IDs.
+
+ This API only has a single access mode, application-restricted - signed JWT authentication, through which you may:
+
+ * Create a product team
+ * Create a product
+ * Retrieve details about a product team
+ * Retrieve details about a product
+ * Retrieve a list of all products associated wit a team or all products associated with an organisation, grouped by product team
+ * Delete a product team
+ * Delete a product
## Who can use this API
- This API can only be used where there is a legal basis to do so. Make sure you have a valid use case before you go too far with your development. You must demonstrate you have a valid use case as part of digital onboarding. Connecting Parties must have an appointed Clinical Safety Officer and undertake a Clinical Safety Assessment.
+ Currently this API is for [internal use only](https://digital.nhs.uk/developer/guides-and-documentation/reference-guide#statuses).
## API status and roadmap
- This API is in [development](https://digital.nhs.uk/developer/guides-and-documentation/reference-guide#statuses).
+ This API is in development, meaning:
- To see our roadmap, or to suggest, comment or vote on features for this API, see our interactive [product backlog](https://nhs-digital-api-management.featureupvote.com/).
-
- If you have any other queries, [contact us](https://digital.nhs.uk/developer/help-and-support).
+ * it is available for testing in the integration environment
+ * we expect to make breaking changes based on developer feedback
## Service level
- This API is a platinum service, meaning it is operational and supported 24 hours a day, 365 days a year.
+ This API is a bronze service, meaning it is operational and supported only during business hours (8 am to 6 pm), Monday to Friday excluding bank holidays.
For more details, see [service levels](https://digital.nhs.uk/developer/guides-and-documentation/reference-guide#service-levels).
@@ -96,28 +105,7 @@ info:
## Onboarding
- You need to get your software approved by us before it can go live with this API. We call this onboarding. The onboarding process can sometimes be quite long, so it’s worth planning well ahead.
-
- As part of this process, you need to demonstrate that you can manage risks and that your software conforms technically with the requirements for this API.
-
- Information on this page might impact the design of your software. For details, see [Onboarding support information](https://digital.nhs.uk/developer/api-catalogue/national-record-locator-consumer-fhir/onboarding-support-information).
-
- To understand how our online digital onboarding process works, see [digital onboarding](https://digital.nhs.uk/developer/guides-and-documentation/digital-onboarding#using-the-digital-onboarding-portal).
-
-
-
-
-
-
-
-
-
-
-
-
To get started, sign in or create a developer account, then select 'product onboarding'.
-
-
-
+ This API is not yet available for onboarding.
## Change log
diff --git a/infrastructure/swagger/05_paths.yaml b/infrastructure/swagger/05_paths.yaml
index ebc750240..c9c563b45 100644
--- a/infrastructure/swagger/05_paths.yaml
+++ b/infrastructure/swagger/05_paths.yaml
@@ -30,7 +30,7 @@ paths:
"200":
$ref: "#/components/responses/StatusOK"
"404":
- $ref: "#/components/responses/NotFound"
+ description: _status not found
parameters:
- $ref: "#/components/parameters/HeaderVersion"
- $ref: "#/components/parameters/HeaderRequestId"
@@ -128,7 +128,7 @@ paths:
"200":
$ref: "#/components/responses/CPMProductTeamRead"
"404":
- $ref: "#/components/responses/NotFound"
+ $ref: "#/components/responses/ProductTeamNotFound"
x-amazon-apigateway-integration:
<<: *ApiGatewayIntegration
uri: ${method_readProductTeam}
@@ -151,7 +151,7 @@ paths:
"200":
$ref: "#/components/responses/CpmProductTeamDelete"
"404":
- $ref: "#/components/responses/NotFound"
+ $ref: "#/components/responses/ProductTeamNotFound"
"409":
$ref: "#/components/responses/Conflict"
x-amazon-apigateway-integration:
@@ -225,9 +225,9 @@ paths:
"201":
$ref: "#/components/responses/ProductCreate"
"400":
- $ref: "#/components/responses/BadRequest"
+ $ref: "#/components/responses/CreateProductBadRequest"
"404":
- $ref: "#/components/responses/NotFound"
+ $ref: "#/components/responses/ProductTeamNotFound"
x-amazon-apigateway-integration:
<<: *ApiGatewayIntegration
uri: ${method_createCpmProduct}
@@ -356,7 +356,7 @@ paths:
"200":
$ref: "#/components/responses/ProductRead"
"404":
- $ref: "#/components/responses/NotFound"
+ $ref: "#/components/responses/ProductNotFound"
x-amazon-apigateway-integration:
<<: *ApiGatewayIntegration
uri: ${method_readCpmProduct}
@@ -424,7 +424,7 @@ paths:
"200":
$ref: "#/components/responses/ProductDelete"
"404":
- $ref: "#/components/responses/NotFound"
+ $ref: "#/components/responses/ProductDeleteNotFound"
x-amazon-apigateway-integration:
<<: *ApiGatewayIntegration
uri: ${method_deleteCpmProduct}
diff --git a/infrastructure/swagger/07_components--schemas--domain.yaml b/infrastructure/swagger/07_components--schemas--domain.yaml
index 4de100633..ba5b71dc8 100644
--- a/infrastructure/swagger/07_components--schemas--domain.yaml
+++ b/infrastructure/swagger/07_components--schemas--domain.yaml
@@ -81,10 +81,10 @@ components:
type: string
name:
type: string
- cpm_product_team_id:
- type: string
product_team_id:
type: string
+ cpm_product_team_id:
+ type: string
ods_code:
type: string
status:
@@ -142,6 +142,8 @@ components:
items:
type: object
properties:
+ cpm_product_team_id:
+ type: string
product_team_id:
type: string
products:
@@ -178,12 +180,13 @@ components:
nullable: true
example:
results:
- - org_code: "xyzzy"
+ - org_code: "F5H1R"
product_teams:
- - product_team_id: "1234"
+ - product_team_id: "55e86121-3826-468c-a6f0-dd0f1fbc0259"
+ cpm_product_team_id: "a9a9694d-001b-45ce-9f2a-6c9bf80ae0d0"
products:
- - id: "P.123"
- product_team_id: "1234"
+ - id: "P.1X3-XYZ"
+ product_team_id: "55e86121-3826-468c-a6f0-dd0f1fbc0259"
name: "My Great Product 1"
ods_code: "F5H1R"
status: "active"
@@ -191,10 +194,11 @@ components:
updated_on: "null"
deleted_on: "null"
keys: []
- - product_team_id: "5678"
+ - product_team_id: "24ac1857-f718-4905-813f-52da930c3ea1"
+ cpm_product_team_id: "152705aa-0342-487f-a654-64bba814a847"
products:
- - id: "P.xyz"
- product_team_id: "5678"
+ - id: "P.4Y6-ABC"
+ product_team_id: "24ac1857-f718-4905-813f-52da930c3ea1"
name: "My Great Product 3"
ods_code: "F5H1R"
status: "active"
diff --git a/infrastructure/swagger/10_components--parameters--path.yaml b/infrastructure/swagger/10_components--parameters--path.yaml
index f8118bfb3..9bfdba1cc 100644
--- a/infrastructure/swagger/10_components--parameters--path.yaml
+++ b/infrastructure/swagger/10_components--parameters--path.yaml
@@ -5,13 +5,13 @@ components:
name: product_team_id
in: path
required: true
- description: product team identifier
+ description: Product Team identifier. Either the "internally" generated id (cpm_product_team_id) or the provided team id (product_team_id)
schema:
type: string
ProductId:
name: product_id
in: path
required: true
- description: product identifier
+ description: The Product identifier generated at time of creation.
schema:
type: string
diff --git a/infrastructure/swagger/12_components--responses.yaml b/infrastructure/swagger/12_components--responses.yaml
index cebc2af0d..82b05e9f6 100644
--- a/infrastructure/swagger/12_components--responses.yaml
+++ b/infrastructure/swagger/12_components--responses.yaml
@@ -20,8 +20,8 @@ components:
$ref: "#/components/schemas/StatusOK"
headers:
<<: *ResponseHeaders
- NotFound:
- description: Not found
+ ProductTeamNotFound:
+ description: Product Team has not been found
content:
application/json:
schema:
@@ -29,7 +29,34 @@ components:
example:
errors:
- code: "RESOURCE_NOT_FOUND"
- message: "Could not find for key ('')"
+ message: "Could not find ProductTeam for key ('f9518c12-6c83-4544-97db-d9dd1d64da97')"
+ ProductNotFound:
+ description: Product has not been found
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ErrorResponse"
+ example:
+ errors:
+ - code: "RESOURCE_NOT_FOUND"
+ message: "Could not find CpmProduct for key ('P.XXX-YYY')"
+ ProductDeleteNotFound:
+ description: Product has not been found
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ErrorResponse"
+ examples:
+ ProductTeamNotFound:
+ value:
+ errors:
+ - code: "RESOURCE_NOT_FOUND"
+ message: "Could not find ProductTeam for key ('f9518c12-6c83-4544-97db-d9dd1d64da97')"
+ ProductNotFound:
+ value:
+ errors:
+ - code: "RESOURCE_NOT_FOUND"
+ message: "Could not find CpmProduct for key ('f9518c12-6c83-4544-97db-d9dd1d64da97', 'P.XXX-YYY')"
Conflict:
description: Conflict
content:
@@ -39,7 +66,7 @@ components:
example:
errors:
- code: "CONFLICT"
- message: "Product Team cannot be deleted as it still has associated Product Ids ['P.123-XYZ', 'P.456-ABC']"
+ message: "Product Team cannot be deleted as it still has associated Product Ids ['P.1X3-XYZ', 'P.4Y6-ABC']"
BadRequest:
description: Bad request (multiple error types)
content:
@@ -103,6 +130,33 @@ components:
errors:
- code: "MISSING_VALUE"
message: "CreateProductTeamIncomingParams.ods_code: field required"
+ CreateProductBadRequest:
+ description: createProduct Bad request
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ErrorResponse"
+ examples:
+ MissingValue:
+ value:
+ errors:
+ - code: "MISSING_VALUE"
+ message: "CreateCpmProductIncomingParams.name: field required"
+ ExtraFieldsValidationError:
+ value:
+ errors:
+ - code: "VALIDATION_ERROR"
+ message: "CreateCpmProductIncomingParams.extra_name: extra fields not permitted"
+ EmptyValueValidationError:
+ value:
+ errors:
+ - code: "VALIDATION_ERROR"
+ message: "CreateCpmProductIncomingParams.name: ensure this value has at least 1 characters"
+ InvalidJSONValidationError:
+ value:
+ errors:
+ - code: "VALIDATION_ERROR"
+ message: "Invalid JSON body was provided: line 1 column 20 (char 19)"
headers:
Access-Control-Allow-Origin:
schema:
diff --git a/infrastructure/swagger/13_components--parameters--query.yaml b/infrastructure/swagger/13_components--parameters--query.yaml
index f84cc9d8a..ddbd66769 100644
--- a/infrastructure/swagger/13_components--parameters--query.yaml
+++ b/infrastructure/swagger/13_components--parameters--query.yaml
@@ -5,7 +5,7 @@ components:
name: product_team_id
in: query
required: false
- description: The ID of the product team to filter results by.
+ description: Product Team identifier to filter results by. Either the "internally" generated id (cpm_product_team_id) or the provided team id (product_team_id)
schema:
type: string
OrganisationCodeQuery:
diff --git a/pyproject.toml b/pyproject.toml
index 98c201739..731632935 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "connecting-party-manager"
-version = "2025.03.07"
+version = "2025.03.10"
description = "Repository for the Connecting Party Manager API and related services"
authors = ["NHS England"]
license = "LICENSE.md"
diff --git a/scripts/UI/ui.mk b/scripts/UI/ui.mk
new file mode 100644
index 000000000..fe0396053
--- /dev/null
+++ b/scripts/UI/ui.mk
@@ -0,0 +1,4 @@
+.PHONY: run--ui
+
+run--ui: ## Run the CPM test UI on localhost
+ npm run --prefix test_ui/product_id_flow dev
diff --git a/scripts/infrastructure/apigee/apigee.sh b/scripts/infrastructure/apigee/apigee.sh
index a6d8cb917..272e6a334 100644
--- a/scripts/infrastructure/apigee/apigee.sh
+++ b/scripts/infrastructure/apigee/apigee.sh
@@ -100,6 +100,9 @@ function attach_product(){
_product_name="connecting-party-manager--$_apigee_environment--$API_NAME--app-level0"
_secret_name="$_aws_environment--apigee-app-client-info"
_apigee_stage=$(get_apigee_stage ${_workspace_name})
+ external_id_secret_name="nhse-cpm--mgmt--${_aws_environment}-external-id"
+ external_id=$(aws secretsmanager get-secret-value --secret-id $external_id_secret_name --query SecretString --output text)
+
echo "
@@ -118,7 +121,7 @@ function attach_product(){
session_name="attach-product-session"
duration_seconds=900
- assume_role_output=$(aws sts assume-role --role-arn "$role_arn" --role-session-name "$session_name" --duration-seconds "$duration_seconds")
+ assume_role_output=$(aws sts assume-role --role-arn "$role_arn" --role-session-name "$session_name" --external-id "$external_id" --duration-seconds "$duration_seconds")
# Check if the assume-role command was successful
if [ $? -eq 0 ]; then
@@ -183,6 +186,8 @@ function detach_product(){
_product_name="connecting-party-manager--$_apigee_environment--$API_NAME--app-level0"
_secret_name="$_aws_environment--apigee-app-client-info"
_apigee_stage=$(get_apigee_stage ${_workspace_name})
+ external_id_secret_name="nhse-cpm--mgmt--${_aws_environment}-external-id"
+ external_id=$(aws secretsmanager get-secret-value --secret-id $external_id_secret_name --query SecretString --output text)
echo "
@@ -201,7 +206,7 @@ function detach_product(){
session_name="attach-product-session"
duration_seconds=900
- assume_role_output=$(aws sts assume-role --role-arn "$role_arn" --role-session-name "$session_name" --duration-seconds "$duration_seconds")
+ assume_role_output=$(aws sts assume-role --role-arn "$role_arn" --role-session-name "$session_name" --external-id "$external_id" --duration-seconds "$duration_seconds")
# Check if the assume-role command was successful
if [ $? -eq 0 ]; then
diff --git a/scripts/infrastructure/destroy/destroy-corrupted-workspace.sh b/scripts/infrastructure/destroy/destroy-corrupted-workspace.sh
index 7f0f1428e..efc365de5 100644
--- a/scripts/infrastructure/destroy/destroy-corrupted-workspace.sh
+++ b/scripts/infrastructure/destroy/destroy-corrupted-workspace.sh
@@ -27,7 +27,10 @@ function _destroy_corrupted_workspace() {
role_arn="arn:aws:iam::${dev_acct}:role/${TERRAFORM_ROLE_NAME}"
session_name="resource-search-session"
duration_seconds=900
- assume_role_output=$(aws sts assume-role --role-arn "$role_arn" --role-session-name "$session_name" --duration-seconds "$duration_seconds")
+ external_id_secret_name="nhse-cpm--mgmt--${ENV}-external-id"
+ external_id=$(aws secretsmanager get-secret-value --secret-id $external_id_secret_name --query SecretString --output text)
+
+ assume_role_output=$(aws sts assume-role --role-arn "$role_arn" --role-session-name "$session_name" --external-id "$external_id" --duration-seconds "$duration_seconds")
# Check if the assume-role command was successful
if [ $? -eq 0 ]; then
diff --git a/scripts/infrastructure/destroy/destroy-expired-workspaces.sh b/scripts/infrastructure/destroy/destroy-expired-workspaces.sh
index 18999e727..9fadf990a 100644
--- a/scripts/infrastructure/destroy/destroy-expired-workspaces.sh
+++ b/scripts/infrastructure/destroy/destroy-expired-workspaces.sh
@@ -11,7 +11,11 @@ function _destroy_expired_workspaces() {
role_arn="arn:aws:iam::${dev_acct}:role/NHSDeploymentRole"
session_name="resource-search-session"
duration_seconds=900
- assume_role_output=$(aws sts assume-role --role-arn "$role_arn" --role-session-name "$session_name" --duration-seconds "$duration_seconds")
+
+ external_id_secret_name="nhse-cpm--mgmt--${ENV}-external-id"
+ external_id=$(aws secretsmanager get-secret-value --secret-id $external_id_secret_name --query SecretString --output text)
+
+ assume_role_output=$(aws sts assume-role --role-arn "$role_arn" --role-session-name "$session_name" --external-id "$external_id" --duration-seconds "$duration_seconds")
# Check if the assume-role command was successful
if [ $? -eq 0 ]; then
diff --git a/src/api/searchProduct/tests/test_index.py b/src/api/searchProduct/tests/test_index.py
index 6a84b6987..5b88bd5bf 100644
--- a/src/api/searchProduct/tests/test_index.py
+++ b/src/api/searchProduct/tests/test_index.py
@@ -135,7 +135,8 @@ def test_search_by_product_team_id():
"org_code": ODS_CODE,
"product_teams": [
{
- "product_team_id": product_team.id,
+ "product_team_id": None,
+ "cpm_product_team_id": product_team.id,
"products": [cpm_product.state()],
},
],
@@ -209,7 +210,8 @@ def test_search_by_product_team_alias():
"org_code": ODS_CODE,
"product_teams": [
{
- "product_team_id": product_team.id,
+ "product_team_id": "808a36db-a52a-4130-b71e-d9cbcbaed15b",
+ "cpm_product_team_id": product_team.id,
"products": [cpm_product.state()],
},
],
@@ -284,7 +286,8 @@ def test_index_org_code():
"org_code": ODS_CODE,
"product_teams": [
{
- "product_team_id": product_team.id,
+ "product_team_id": "808a36db-a52a-4130-b71e-d9cbcbaed15b",
+ "cpm_product_team_id": product_team.id,
"products": [cpm_product.state()],
},
],
@@ -419,11 +422,13 @@ def test_index_org_code_multiple_product_teams():
"org_code": ODS_CODE,
"product_teams": [
{
- "product_team_id": product_team_1.id,
+ "product_team_id": "808a36db-a52a-4130-b71e-d9cbcbaed15b",
+ "cpm_product_team_id": product_team_1.id,
"products": [cpm_product_1.state()],
},
{
- "product_team_id": product_team_2.id,
+ "product_team_id": None,
+ "cpm_product_team_id": product_team_2.id,
"products": [cpm_product_2.state()],
},
],
@@ -434,9 +439,8 @@ def test_index_org_code_multiple_product_teams():
# Ensure expected product teams are sorted
expected_product_teams = sorted(
expected_response["results"][0]["product_teams"],
- key=lambda team: team["product_team_id"],
+ key=lambda team: team["cpm_product_team_id"],
)
-
# Sort the products within each product team in the expected response
for team in expected_product_teams:
team["products"] = sorted(team["products"], key=lambda product: product["id"])
diff --git a/src/api/tests/feature_tests/features/searchCpmProduct.success.feature b/src/api/tests/feature_tests/features/searchCpmProduct.success.feature
index 8cda8cbd8..0a0bf0396 100644
--- a/src/api/tests/feature_tests/features/searchCpmProduct.success.feature
+++ b/src/api/tests/feature_tests/features/searchCpmProduct.success.feature
@@ -36,11 +36,12 @@ Feature: Search Products - success scenarios
| path | value |
| name | My Great Product |
And I note the response field "$.id" as "product_id"
- When I make a "GET" request with "default" headers to "Product?product_team_id=${ note(product_team_id) }"
+ When I make a "GET" request with "default" headers to "Product?product_team_id="
Then I receive a status code "200" with body
| path | value |
| results.0.org_code | F5H1R |
- | results.0.product_teams.0.product_team_id | ${ note(product_team_id) } |
+ | results.0.product_teams.0.product_team_id | 808a36db-a52a-4130-b71e-d9cbcbaed15b |
+ | results.0.product_teams.0.cpm_product_team_id | ${ note(product_team_id) } |
| results.0.product_teams.0.products.0.id | ${ note(product_id) } |
| results.0.product_teams.0.products.0.cpm_product_team_id | ${ note(product_team_id) } |
| results.0.product_teams.0.products.0.product_team_id | 808a36db-a52a-4130-b71e-d9cbcbaed15b |
@@ -54,7 +55,7 @@ Feature: Search Products - success scenarios
And the response headers contain:
| name | value |
| Content-Type | application/json |
- | Content-Length | 444 |
+ | Content-Length | 507 |
Examples:
| product_team_id |
@@ -77,7 +78,8 @@ Feature: Search Products - success scenarios
Then I receive a status code "200" with body
| path | value |
| results.0.org_code | F5H1R |
- | results.0.product_teams.0.product_team_id | ${ note(product_team_id) } |
+ | results.0.product_teams.0.product_team_id | 808a36db-a52a-4130-b71e-d9cbcbaed15b |
+ | results.0.product_teams.0.cpm_product_team_id | ${ note(product_team_id) } |
| results.0.product_teams.0.products.0.id | ${ note(product_id) } |
| results.0.product_teams.0.products.0.cpm_product_team_id | ${ note(product_team_id) } |
| results.0.product_teams.0.products.0.product_team_id | 808a36db-a52a-4130-b71e-d9cbcbaed15b |
@@ -91,7 +93,7 @@ Feature: Search Products - success scenarios
And the response headers contain:
| name | value |
| Content-Type | application/json |
- | Content-Length | 444 |
+ | Content-Length | 507 |
Scenario Outline: Successfully search more than one Product with product team id or alias
Given I have already made a "POST" request with "default" headers to "ProductTeam" with body:
@@ -117,7 +119,8 @@ Feature: Search Products - success scenarios
Then I receive a status code "200" with body where ProductTeams has a length of "1" with "3" Products each
| path | value |
| results.0.org_code | F5H1R |
- | results.0.product_teams.0.product_team_id | ${ note(product_team_id) } |
+ | results.0.product_teams.0.product_team_id | 808a36db-a52a-4130-b71e-d9cbcbaed15b |
+ | results.0.product_teams.0.cpm_product_team_id | ${ note(product_team_id) } |
| results.0.product_teams.0.products.0.id | ${ note(product_id_1) } |
| results.0.product_teams.0.products.0.cpm_product_team_id | ${ note(product_team_id) } |
| results.0.product_teams.0.products.0.product_team_id | 808a36db-a52a-4130-b71e-d9cbcbaed15b |
@@ -151,7 +154,7 @@ Feature: Search Products - success scenarios
And the response headers contain:
| name | value |
| Content-Type | application/json |
- | Content-Length | 1078 |
+ | Content-Length | 1141 |
Examples:
| product_team_id |
@@ -181,7 +184,8 @@ Feature: Search Products - success scenarios
Then I receive a status code "200" with body where ProductTeams has a length of "2" with "2" Products each
| path | value |
| results.0.org_code | F5H1R |
- | results.0.product_teams.0.product_team_id | ${ note(product_team_id_1) } |
+ | results.0.product_teams.0.product_team_id | null |
+ | results.0.product_teams.0.cpm_product_team_id | ${ note(product_team_id_1) } |
| results.0.product_teams.0.products.0.id | ${ note(product_id_1) } |
| results.0.product_teams.0.products.0.cpm_product_team_id | ${ note(product_team_id_1) } |
| results.0.product_teams.0.products.0.product_team_id | null |
@@ -192,7 +196,8 @@ Feature: Search Products - success scenarios
| results.0.product_teams.0.products.0.updated_on | null |
| results.0.product_teams.0.products.0.deleted_on | null |
| results.0.product_teams.0.products.0.keys | [] |
- | results.0.product_teams.1.product_team_id | ${ note(product_team_id_2) } |
+ | results.0.product_teams.1.product_team_id | null |
+ | results.0.product_teams.1.cpm_product_team_id | ${ note(product_team_id_2) } |
| results.0.product_teams.1.products.0.id | ${ note(product_id_2) } |
| results.0.product_teams.1.products.0.cpm_product_team_id | ${ note(product_team_id_2) } |
| results.0.product_teams.1.products.0.product_team_id | null |
@@ -206,7 +211,7 @@ Feature: Search Products - success scenarios
And the response headers contain:
| name | value |
| Content-Type | application/json |
- | Content-Length | 769 |
+ | Content-Length | 827 |
Scenario: Deleted Products not returned in search
Given I have already made a "POST" request with "default" headers to "ProductTeam" with body:
@@ -233,7 +238,8 @@ Feature: Search Products - success scenarios
Then I receive a status code "200" with body where ProductTeams has a length of "1" with "2" Products each
| path | value |
| results.0.org_code | F5H1R |
- | results.0.product_teams.0.product_team_id | ${ note(product_team_id) } |
+ | results.0.product_teams.0.product_team_id | 808a36db-a52a-4130-b71e-d9cbcbaed15b |
+ | results.0.product_teams.0.cpm_product_team_id | ${ note(product_team_id) } |
| results.0.product_teams.0.products.0.id | ${ note(product_id_1) } |
| results.0.product_teams.0.products.0.cpm_product_team_id | ${ note(product_team_id) } |
| results.0.product_teams.0.products.0.product_team_id | 808a36db-a52a-4130-b71e-d9cbcbaed15b |
@@ -257,4 +263,4 @@ Feature: Search Products - success scenarios
And the response headers contain:
| name | value |
| Content-Type | application/json |
- | Content-Length | 762 |
+ | Content-Length | 825 |
diff --git a/src/api/tests/feature_tests/steps/steps.py b/src/api/tests/feature_tests/steps/steps.py
index d7c16d59c..3a826c60c 100644
--- a/src/api/tests/feature_tests/steps/steps.py
+++ b/src/api/tests/feature_tests/steps/steps.py
@@ -235,11 +235,11 @@ def then_response(
# Sort product teams by "product_team_id"
expected_body["results"][0]["product_teams"] = sorted(
expected_body["results"][0]["product_teams"],
- key=lambda team: team["product_team_id"],
+ key=lambda team: team["cpm_product_team_id"],
)
response_body["results"][0]["product_teams"] = sorted(
response_body["results"][0]["product_teams"],
- key=lambda team: team["product_team_id"],
+ key=lambda team: team["cpm_product_team_id"],
)
# Sort products inside each product team by "id"
diff --git a/src/layers/domain/response/response_models.py b/src/layers/domain/response/response_models.py
index cdb9da87f..959c772d3 100644
--- a/src/layers/domain/response/response_models.py
+++ b/src/layers/domain/response/response_models.py
@@ -19,18 +19,20 @@ def _group_products(self, products: list[dict]) -> list[dict]:
for product in product_dicts:
org_code = product["ods_code"]
- team_id = product["cpm_product_team_id"]
+ product_team_id = product["product_team_id"]
+ cpm_team_id = product["cpm_product_team_id"]
if org_code not in organisations:
organisations[org_code] = {"org_code": org_code, "product_teams": {}}
- if team_id not in organisations[org_code]["product_teams"]:
- organisations[org_code]["product_teams"][team_id] = {
- "product_team_id": team_id,
+ if cpm_team_id not in organisations[org_code]["product_teams"]:
+ organisations[org_code]["product_teams"][cpm_team_id] = {
+ "product_team_id": product_team_id,
+ "cpm_product_team_id": cpm_team_id,
"products": [],
}
- organisations[org_code]["product_teams"][team_id]["products"].append(
+ organisations[org_code]["product_teams"][cpm_team_id]["products"].append(
product
)
@@ -41,7 +43,7 @@ def _group_products(self, products: list[dict]) -> list[dict]:
"org_code": org["org_code"],
"product_teams": sorted(
list(org["product_teams"].values()),
- key=lambda team: team["product_team_id"],
+ key=lambda team: team["cpm_product_team_id"],
),
}
for org in organisations.values()
diff --git a/test_ui/product_id_flow/index.html b/test_ui/product_id_flow/index.html
index 1ba4c5ab4..8ce2d0b72 100644
--- a/test_ui/product_id_flow/index.html
+++ b/test_ui/product_id_flow/index.html
@@ -3,7 +3,7 @@
- NHS Product Team Creation
+ NHS Product ID demos