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
55 changes: 48 additions & 7 deletions docs/mhr-api-internal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,46 @@ paths:
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'

'/mhr/api/v1/documents/qs-document-ids':
parameters:
- $ref: '#/components/parameters/accountId'
get:
tags:
- Registration
summary: Retrieve a Qualified Supplier document ID for a new staff review registration.
description: For MHR registrations that are submitted by qualified suppliers and reviewed by staff, retrieve a document ID to save in DRS before the registration is submitted for review. Intended to only be called once per registration, and only when the registration is submitted by a qualified supplier and will be reviewed by staff.
operationId: get-qs-document-id
responses:
'200':
description: OK
headers:
Access-Control-Allow-Origin:
$ref: '#/components/headers/AccessControlAllowOrigin'
Access-Control-Allow-Methods:
$ref: '#/components/headers/AccessControlAllowMethods'
Access-Control-Allow-Headers:
$ref: '#/components/headers/AccessControlAllowHeaders'
Access-Control-Max-Age:
$ref: '#/components/headers/AccessControlMaxAge'
content:
application/json:
schema:
$ref: '#/components/schemas/documentId'
examples:
/api/v1/documents/qs-document-ids/get:
summary: Request a QS document ID response.
value:
documentId: '10109535'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'

'/mhr/api/v1/documents/verify/{documentId}':
parameters:
- $ref: '#/components/parameters/accountId'
Expand Down Expand Up @@ -3155,13 +3195,7 @@ paths:
$ref: '#/components/responses/InternalServerError'
'/mhr/api/v1/reviews/{reviewId}':
parameters:
- name: reviewId
in: path
description: 'The identifier of a staff review registration. If an invalid value is submitted then the response is a [404] status code.'
required: true
schema:
type: string
example: '123'
- $ref: '#/components/parameters/reviewId'
- name: Account-Id
in: header
description: The account that the user is operating on behalf of.
Expand Down Expand Up @@ -5178,6 +5212,13 @@ components:
csaStandard: 'Z240,'
rebuiltRemarks: 'REBUILT AS A DOUBLE WIDE, MAKE/MODEL CUSTOM, YEAR 1995'
otherRemarks: 'BC SAFETY AUTHORITY #339556, PERMIT# EL-721296-2018'
documentId:
type: object
description: The unique identifier of one or more documents that are associated with a single MH registration.
properties:
documentId:
type: string
example: '10590422'
documentSummary:
title: documentSummary
type: object
Expand Down
2 changes: 1 addition & 1 deletion mhr-api/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mhr-api"
version = "2.1.10"
version = "2.1.11"
description = ""
authors = ["dlovett <doug@daxiom.com>"]
license = "BSD 3"
Expand Down
12 changes: 12 additions & 0 deletions mhr-api/src/mhr_api/models/registration_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@
SORT_DESCENDING = "descending"
DOC_ID_QUALIFIED_CLAUSE = ", get_mhr_doc_qualified_id() AS doc_id"
DOC_ID_MANUFACTURER_CLAUSE = ", get_mhr_doc_manufacturer_id() AS doc_id"
QUERY_NEXT_QUALIFIED_DOC_ID = "select get_mhr_doc_qualified_id()"
QUERY_NEXT_MANUFACTURER_DOC_ID = "select get_mhr_doc_manufacturer_id()"
DOC_ID_GOV_AGENT_CLAUSE = ", get_mhr_doc_gov_agent_id() AS doc_id"
DOC_ID_STAFF_CLAUSE = ", get_mhr_doc_staff_id() AS doc_id"
BATCH_DOC_NAME_MANUFACTURER_MHREG = "batch-manufacturer-mhreg-report-{time}.pdf"
Expand Down Expand Up @@ -442,6 +444,16 @@ def get_change_generated_values(registration, draft, user_group: str = None, sta
return registration


def get_qs_document_id(user_group: str) -> str:
"""Get db generated qualifed supplier document ID based on the user group. Only intended for DRS integration."""
query: str = QUERY_NEXT_QUALIFIED_DOC_ID
if user_group is not None and user_group == MANUFACTURER_GROUP:
query = QUERY_NEXT_MANUFACTURER_DOC_ID
result = db.session.execute(text(query))
row = result.first()
return str(row[0])


def get_registration_id() -> int:
"""Get db generated registration id, initially for creating a manufacturer."""
result = db.session.execute(text(QUERY_REG_ID_PKEY))
Expand Down
30 changes: 29 additions & 1 deletion mhr-api/src/mhr_api/resources/v1/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@

from http import HTTPStatus

from flask import Blueprint, request
from flask import Blueprint, jsonify, request
from flask_cors import cross_origin

from mhr_api.exceptions import BusinessException, DatabaseException
from mhr_api.models import MhrRegistration
from mhr_api.models.registration_utils import get_qs_document_id
from mhr_api.models.type_tables import MhrRegistrationTypes
from mhr_api.reports.v2.report_utils import ReportTypes
from mhr_api.resources import registration_utils as reg_utils
Expand Down Expand Up @@ -129,6 +130,33 @@ def get_documents(document_id: str): # pylint: disable=too-many-return-statemen
return resource_utils.default_exception_response(default_exception)


@bp.route("/qs-document-ids", methods=["GET", "OPTIONS"])
@cross_origin(origin="*")
@jwt.requires_auth
def get_qs_document_ids():
"""Get a unique qualified supplier document ID based on the user token for DRS integration."""
try:
# Quick check: must provide an account ID.
account_id = resource_utils.get_account_id(request)
if account_id is None:
return resource_utils.account_required_response()
user_group: str = get_group(jwt)
logger.info(f"get next QS document_id starting account_id={account_id} user group={user_group}")
# Verify request JWT and account ID
if not authorized(account_id, jwt):
return resource_utils.unauthorized_error_response(account_id)
if is_staff(jwt):
logger.warning("Get QS document ID endpoint is not intended for staff users.")
doc_id: str = get_qs_document_id(user_group)
logger.info(f"New group {user_group} doc Id={doc_id}")
response_json = {"documentId": doc_id}
return jsonify(response_json), HTTPStatus.OK
except DatabaseException as db_exception:
return resource_utils.db_exception_response(db_exception, account_id, "GET QS document id")
except Exception as default_exception: # noqa: B902; return nicer default error
return resource_utils.default_exception_response(default_exception)


def map_report_type(reg_json: dict, staff: bool) -> str:
"""Map the registration type to the report type."""
if staff:
Expand Down
33 changes: 32 additions & 1 deletion mhr-api/tests/unit/api/test_documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@
import pytest
from flask import current_app

from mhr_api.services.authz import COLIN_ROLE, MHR_ROLE, STAFF_ROLE
from mhr_api.services.authz import MHR_ROLE, STAFF_ROLE, COLIN_ROLE, REQUEST_EXEMPTION_RES, \
TRANSFER_DEATH_JT, TRANSFER_SALE_BENEFICIARY, REQUEST_TRANSPORT_PERMIT, \
REGISTER_MH
from tests.unit.services.utils import create_header, create_header_account


MANUFACTURER_ROLES = [MHR_ROLE, TRANSFER_SALE_BENEFICIARY, REQUEST_TRANSPORT_PERMIT, REGISTER_MH]
QUALIFIED_USER = [MHR_ROLE, REQUEST_EXEMPTION_RES, TRANSFER_DEATH_JT, TRANSFER_SALE_BENEFICIARY]
# testdata pattern is ({desc}, {roles}, {status}, {has_account}, {doc_id}, {exists}, {valid})
TEST_VERIFY_ID_DATA = [
('Missing account', [MHR_ROLE], HTTPStatus.BAD_REQUEST, False, '40583993', True, True),
Expand All @@ -47,6 +51,13 @@
('Not exists no checksum staff', [MHR_ROLE, STAFF_ROLE], HTTPStatus.NOT_FOUND, True, '1001000000'),
('Invalid checksum', [MHR_ROLE], HTTPStatus.BAD_REQUEST, True, '79289200')
]
# testdata pattern is ({desc}, {roles}, {status}, {has_account}, {start_digit})
TEST_DATA_QS_DOC_ID_DATA = [
('Missing account', [MHR_ROLE], HTTPStatus.BAD_REQUEST, False, None),
('Invalid role', [COLIN_ROLE], HTTPStatus.UNAUTHORIZED, True, None),
('Valid request QS lawyyer/notary', QUALIFIED_USER, HTTPStatus.OK, True, '1'),
('Valid request QS manufacturer', MANUFACTURER_ROLES, HTTPStatus.OK, True, '8'),
]


@pytest.mark.parametrize('desc,roles,status,has_account,doc_id,exists,valid', TEST_VERIFY_ID_DATA)
Expand Down Expand Up @@ -93,3 +104,23 @@ def test_get_document(session, client, jwt, desc, roles, status, has_account, do
current_app.logger.debug(response)
assert response
assert response['documentId'] == doc_id


@pytest.mark.parametrize('desc,roles,status,has_account,start_digit', TEST_DATA_QS_DOC_ID_DATA)
def test_get_qs_doc_id(session, client, jwt, desc, roles, status, has_account, start_digit):
"""Assert that the get QS document id endpoint works as expected."""
headers = None
# setup
if has_account:
headers = create_header_account(jwt, roles)
else:
headers = create_header(jwt, roles)
# test
rv = client.get('/api/v1/documents/qs-document-ids',headers=headers)

# check
assert rv.status_code == status
if rv.status_code == HTTPStatus.OK:
response = rv.json
assert response
assert str(response.get("documentId")).startswith(start_digit)
14 changes: 14 additions & 0 deletions mhr-api/tests/unit/models/test_registration_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@
('Invalid exists', '000900', False),
('Invalid too high', '999900', False)
]
# testdata pattern is ({description}, {group_id}, {start_digit})
TEST_DATA_DOC_ID = [
('QS Dealer', DEALERSHIP_GROUP, '1'),
('QS lawyer/notary', QUALIFIED_USER_GROUP, '1'),
('QS manufacturer', MANUFACTURER_GROUP, '8')
]
# testdata pattern is ({account_id}, {sort_criteria}, {sort_order}, {mhr_numbers}, {expected_clause})
TEST_QUERY_ORDER_DATA = [
('PS12345', None, None, "'000900'", queries.REG_ORDER_BY_DATE),
Expand Down Expand Up @@ -303,6 +309,14 @@ def test_validate_mhr_number(session, desc, mhr_number, valid):
assert result == valid


@pytest.mark.parametrize('desc, user_group, start_digit', TEST_DATA_DOC_ID)
def test_qs_doc_id(session, desc, user_group, start_digit):
"""Assert that the QS get next document id works as expected."""
result: str = reg_utils.get_qs_document_id(user_group)
assert result
assert result.startswith(start_digit)


@pytest.mark.parametrize('account_id,sort_criteria,sort_order,mhr_numbers,expected_clause', TEST_QUERY_ORDER_DATA)
def test_account_reg_order(session, account_id, sort_criteria, sort_order, mhr_numbers, expected_clause):
"""Assert that account registration query order by clause is as expected."""
Expand Down
Loading