From bd0ef333096afd85f1ae0d47d2503872ed22dc30 Mon Sep 17 00:00:00 2001 From: Doug Lovett Date: Tue, 14 Jun 2022 12:51:36 -0700 Subject: [PATCH] Schema changes to support MHR create registrations. (#27) Signed-off-by: Doug Lovett --- .../example_data/mhr/__init__.py | 2 + .../example_data/mhr/schema_data.py | 13 +++ .../schemas/common/party.json | 7 ++ .../schemas/mhr/baseInformation.json | 4 + .../schemas/mhr/registration.json | 11 ++- .../schemas/mhr/registrationSummary.json | 50 ++++++++++ .../schemas/ppr/vehicleCollateral.json | 2 +- tests/unit/common/test_party.py | 33 +++++++ tests/unit/mhr/test_base_information.py | 22 +++-- tests/unit/mhr/test_registration.py | 96 ++++++++++++++++++- tests/unit/mhr/test_registration_summary.py | 94 ++++++++++++++++++ tests/unit/ppr/test_vehicle_collateral.py | 1 + 12 files changed, 322 insertions(+), 13 deletions(-) create mode 100644 src/registry_schemas/schemas/mhr/registrationSummary.json create mode 100644 tests/unit/mhr/test_registration_summary.py diff --git a/src/registry_schemas/example_data/mhr/__init__.py b/src/registry_schemas/example_data/mhr/__init__.py index 7719866..ca0d87b 100644 --- a/src/registry_schemas/example_data/mhr/__init__.py +++ b/src/registry_schemas/example_data/mhr/__init__.py @@ -25,6 +25,7 @@ PAYMENT, PERSON_NAME, REGISTRATION, + REGISTRATION_SUMMARY, SEARCH_DETAIL_RESULT, SEARCH_QUERY, SEARCH_QUERY_RESULT, @@ -43,6 +44,7 @@ 'PAYMENT', 'PERSON_NAME', 'REGISTRATION', + 'REGISTRATION_SUMMARY', 'SEARCH_DETAIL_RESULT', 'SEARCH_QUERY', 'SEARCH_QUERY_RESULT', diff --git a/src/registry_schemas/example_data/mhr/schema_data.py b/src/registry_schemas/example_data/mhr/schema_data.py index 19e0c99..b10dca5 100644 --- a/src/registry_schemas/example_data/mhr/schema_data.py +++ b/src/registry_schemas/example_data/mhr/schema_data.py @@ -176,6 +176,19 @@ } } +REGISTRATION_SUMMARY = [ + { + 'mhrNumber': '002000', + 'statusType': 'R', + 'clientReferenceId': 'T-0000001', + 'path': '/mhr/api/v1/registrations/002000', + 'createDateTime': '2021-06-03T22:58:45+00:00', + 'registeringParty': 'Bank of British Columbia', + 'securedParties': 'Bank of British Columbia', + 'inUserList': False + } +] + SEARCH_DETAIL_RESULT = { 'searchDateTime': '2020-05-14T21:08:32+00:00', 'totalResultsSize': 1, diff --git a/src/registry_schemas/schemas/common/party.json b/src/registry_schemas/schemas/common/party.json index 25db468..d728419 100644 --- a/src/registry_schemas/schemas/common/party.json +++ b/src/registry_schemas/schemas/common/party.json @@ -37,6 +37,13 @@ "format": "email", "maxLength": 250, "description": "The email address of the individual or business." + }, + "phoneNumber": { + "type": "string", + "minLength": 10, + "maxLength": 25, + "description": "Free form text with area code for the party contact phone number. May include an extension.", + "example": "2504772734" } }, "anyOf":[ diff --git a/src/registry_schemas/schemas/mhr/baseInformation.json b/src/registry_schemas/schemas/mhr/baseInformation.json index 81556eb..e1042ea 100644 --- a/src/registry_schemas/schemas/mhr/baseInformation.json +++ b/src/registry_schemas/schemas/mhr/baseInformation.json @@ -19,6 +19,10 @@ "type": [ "string", "null" ], "maxLength": 65, "description": "Model name." + }, + "circa": { + "type": [ "boolean", "null" ], + "description": "Indicates the year value is uncertain." } }, "required": [ diff --git a/src/registry_schemas/schemas/mhr/registration.json b/src/registry_schemas/schemas/mhr/registration.json index cfd9423..c935df3 100644 --- a/src/registry_schemas/schemas/mhr/registration.json +++ b/src/registry_schemas/schemas/mhr/registration.json @@ -14,7 +14,7 @@ "type": [ "string", "null" ], "maxLength": 2, "enum": ["C", "D", "E", "R"], - "description": "The status of the registration. C - cancelled?; D - deleted?; E - expired?; R - registered." + "description": "The status of the registration. C - cancelled; D - drafted; E - exempted; R - registered." }, "clientReferenceId": { "type": [ "string", "null" ], @@ -26,6 +26,9 @@ "maxLength": 12, "description": "The declared value of the manufactured home." }, + "registeringParty": { + "$ref": "https://bcrs.gov.bc.ca/.well_known/schemas/common/party" + }, "owners": { "type": "array", "minItems": 1, @@ -45,6 +48,12 @@ "$ref": "https://bcrs.gov.bc.ca/.well_known/schemas/mhr/note" } }, + "pprRegistrations": { + "type": "array", + "items": { + "type": [ "object", "null" ] + } + }, "createDateTime": { "type": [ "string", "null" ], "format": "date-time", diff --git a/src/registry_schemas/schemas/mhr/registrationSummary.json b/src/registry_schemas/schemas/mhr/registrationSummary.json new file mode 100644 index 0000000..8a574fb --- /dev/null +++ b/src/registry_schemas/schemas/mhr/registrationSummary.json @@ -0,0 +1,50 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://bcrs.gov.bc.ca/.well_known/schemas/mhr/registrationSummary", + "type": "object", + "title": "The MHR Registration Summary Schema", + "definitions": {}, + "properties": { + "mhrNumber": { + "type": "string", + "maxLength": 6, + "description": "The MHR Number that uniquely identifies the registration." + }, + "statusType": { + "type": "string", + "maxLength": 3, + "enum": ["R", "C", "D", "E"], + "description": "The status of the Registration. One of " + }, + "path": { + "type": "string", + "maxLength": 150, + "description": "The relative path for a GET request to retrieve an individual registration." + }, + "createDateTime": { + "type": "string", + "format": "date-time", + "description": "Generated by the system, the date and time the registration is created." + }, + "clientReferenceId": { + "type": [ "string", "null" ], + "maxLength": 50, + "description": "An optional client reference identifier associated with the registration. Provided to facilitate client tracking of MHR activity." + }, + "registeringParty": { + "type": "string", + "maxlength": 150, + "description": "The registration Registering Party name." + }, + "inUserList": { + "type": "boolean", + "description": "True if the base registration is already included in the account registrations list." + } + }, + "required": [ + "mhrNumber", + "statusType", + "createDateTime", + "path" + ] +} diff --git a/src/registry_schemas/schemas/ppr/vehicleCollateral.json b/src/registry_schemas/schemas/ppr/vehicleCollateral.json index 7c02075..1433251 100644 --- a/src/registry_schemas/schemas/ppr/vehicleCollateral.json +++ b/src/registry_schemas/schemas/ppr/vehicleCollateral.json @@ -44,7 +44,7 @@ "description": "The unique identifier generated by the PPR system for the Vehicle Collateral record. Returned in the API responses, it is required in requests when removing or modifying Vehicle Collateral with an Amendment Statement or a Change Statement." } }, - "oneOf":[ + "anyOf":[ { "properties": { "type": { "const": "MH" } diff --git a/tests/unit/common/test_party.py b/tests/unit/common/test_party.py index ec8af37..668d075 100644 --- a/tests/unit/common/test_party.py +++ b/tests/unit/common/test_party.py @@ -14,10 +14,25 @@ """Test Suite to ensure the PPR party schema is valid.""" import copy +import pytest + from registry_schemas import validate from registry_schemas.example_data.common import PARTY +# testdata pattern is ({phone number}, {is valid}) +TEST_DATA_PHONE_NUM = [ + ('2504772707', True), + ('250 4772707', True), + ('250 477-2707 ext. 1234', True), + ('250 4772707 extension 123', True), + ('250 477-2707', True), + ('4772707', False), + ('477-2707', False), + ('250477270 12345', False) +] + + def test_valid_party_person(): """Assert that the schema is performing as expected for an individual party.""" is_valid, errors = validate(PARTY, 'party', 'common') @@ -139,3 +154,21 @@ def test_invalid_party_missing_business_address(): print(errors) assert not is_valid + + +@pytest.mark.parametrize('phone_num, valid', TEST_DATA_PHONE_NUM) +def test_phone_number(phone_num, valid): + """Assert that the schema is performing as expected for party phoneNumber.""" + party = copy.deepcopy(PARTY) + party['phoneNumber'] = phone_num + + is_valid, errors = validate(party, 'party', 'common') + + if errors: + for err in errors: + print(err.message) + + if valid: + assert is_valid + else: + assert not is_valid diff --git a/tests/unit/mhr/test_base_information.py b/tests/unit/mhr/test_base_information.py index b2de920..1b9d547 100644 --- a/tests/unit/mhr/test_base_information.py +++ b/tests/unit/mhr/test_base_information.py @@ -18,26 +18,28 @@ from registry_schemas import validate -# testdata pattern is ({desc}, {valid}, {year}, {make}, {model}) +# testdata pattern is ({desc}, {valid}, {year}, {make}, {model}, {circa}) TEST_DATA_BASE_INFO = [ - ('Valid all', True, 1994, 'make', 'model'), - ('Valid no make', True, 1994, None, 'model'), - ('Valid no model', True, 1994, 'make', None), - ('Valid just year', True, 1994, None, None), - ('Missing year', False, None, None, None), - ('Make too long', False, 1994, '0123456789012345678901234567890123456789012345678901234567890123456', None), - ('Model too long', False, 1994, None, '0123456789012345678901234567890123456789012345678901234567890123456') + ('Valid all', True, 1994, 'make', 'model', True), + ('Valid no make', True, 1994, None, 'model', False), + ('Valid no model', True, 1994, 'make', None, None), + ('Valid just year', True, 1994, None, None, False), + ('Missing year', False, None, None, None, None), + ('Make too long', False, 1994, '0123456789012345678901234567890123456789012345678901234567890123456', None, None), + ('Model too long', False, 1994, None, '0123456789012345678901234567890123456789012345678901234567890123456', None) ] -@pytest.mark.parametrize('desc,valid,year,make,model', TEST_DATA_BASE_INFO) -def test_base_info(desc, valid, year, make, model): +@pytest.mark.parametrize('desc,valid,year,make,model,circa', TEST_DATA_BASE_INFO) +def test_base_info(desc, valid, year, make, model, circa): """Assert that the schema is performing as expected.""" data = { 'year': year, 'make': make, 'model': model } + if circa: + data['circa'] = circa is_valid, errors = validate(data, 'baseInformation', 'mhr') if errors: diff --git a/tests/unit/mhr/test_registration.py b/tests/unit/mhr/test_registration.py index 6a078e8..fc11816 100644 --- a/tests/unit/mhr/test_registration.py +++ b/tests/unit/mhr/test_registration.py @@ -20,8 +20,50 @@ from registry_schemas.example_data.mhr import REGISTRATION -# testdata pattern is ({desc},{valid},{mhr},{status},{rev},{decv},{haso},{hasl},{hasd},{hasn},{hasdt},{hasp}) +PARTY_VALID = { + 'personName': { + 'first': 'Michael', + 'middle': 'J', + 'last': 'Smith' + }, + 'address': { + 'street': '520 Johnson St', + 'city': 'Victoria', + 'region': 'BC', + 'country': 'CA', + 'postalCode': 'V8S 2V4' + }, + 'emailAddress': 'msmith@gmail.com', + 'birthDate': '1986-12-01T19:20:20-08:00', + 'phoneNumber': '6042314598' +} +PARTY_INVALID = { + 'personName': { + 'first': 'Michael', + 'middle': 'J', + 'last': 'Smith' + }, + 'address': { + 'street': '520 Johnson St', + 'city': 'Victoria', + 'region': 'BC', + 'country': 'CA', + 'postalCode': 'V8S 2V4' + }, + 'emailAddress': 'msmith@gmail.com', + 'birthDate': '1986-12-01T19:20:20-08:00', + 'phoneNumber': '2314598' +} +PPR_REG_VALID = [ + { + 'reg_data': 'any data allowed' + } +] +PPR_REG_EMPTY = [] + LONG_CLIENT_REF = '01234567890123456789012345678901234567890' + +# testdata pattern is ({desc},{valid},{mhr},{status},{rev},{decv},{haso},{hasl},{hasd},{hasn},{hasdt},{hasp}) TEST_DATA_REG = [ ('Valid request', True, None, None, 'ref', '50000.00', True, True, True, True, False, False), ('Valid response', True, '003456', 'R', 'ref', '50000.00', True, True, True, True, True, True), @@ -37,6 +79,20 @@ ('Invalid declared val too long', False, None, None, 'ref', '1234567890.00', True, True, True, True, False, False) ] +# testdata pattern is ({desc},{valid},{reg_party}) +TEST_DATA_REG_PARTY = [ + ('Valid request with party', True, PARTY_VALID), + ('Invalid request invalid party', False, PARTY_INVALID), + ('Valid request no party', True, None) +] + +# testdata pattern is ({desc},{valid},{ppr_registrations}) +TEST_DATA_PPR_REGISTRATIONS = [ + ('Valid request with ppr registrations', True, PPR_REG_VALID), + ('Valid request empty ppr registrations', True, PPR_REG_EMPTY), + ('Valid request no ppr registrations', True, None) +] + @pytest.mark.parametrize('desc,valid,mhr,status,ref,decv,haso,hasl,hasd,hasn,hasdt,hasp', TEST_DATA_REG) def test_registration(desc, valid, mhr, status, ref, decv, haso, hasl, hasd, hasn, hasdt, hasp): @@ -81,3 +137,41 @@ def test_registration(desc, valid, mhr, status, ref, decv, haso, hasl, hasd, has assert is_valid else: assert not is_valid + + +@pytest.mark.parametrize('desc,valid,reg_party', TEST_DATA_REG_PARTY) +def test_registration_reg_party(desc, valid, reg_party): + """Assert that the schema is performing as expected with a registering party.""" + data = copy.deepcopy(REGISTRATION) + if reg_party: + data['registeringParty'] = reg_party + + is_valid, errors = validate(data, 'registration', 'mhr') + + if errors: + for err in errors: + print(err.message) + + if valid: + assert is_valid + else: + assert not is_valid + + +@pytest.mark.parametrize('desc,valid,ppr_registrations', TEST_DATA_PPR_REGISTRATIONS) +def test_registration_ppr_registrations(desc, valid, ppr_registrations): + """Assert that the schema is performing as expected with a registering party.""" + data = copy.deepcopy(REGISTRATION) + if ppr_registrations: + data['pprRegistrations'] = ppr_registrations + + is_valid, errors = validate(data, 'registration', 'mhr') + + if errors: + for err in errors: + print(err.message) + + if valid: + assert is_valid + else: + assert not is_valid diff --git a/tests/unit/mhr/test_registration_summary.py b/tests/unit/mhr/test_registration_summary.py new file mode 100644 index 0000000..d6d8e31 --- /dev/null +++ b/tests/unit/mhr/test_registration_summary.py @@ -0,0 +1,94 @@ +# Copyright © 2020 Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Test Suite to ensure the MHR registration summary schema is valid.""" +import pytest + +from registry_schemas import validate + + +TEST_VALID_ALL = { + 'mhrNumber': '020000', + 'statusType': 'R', + 'clientReferenceId': 'T-0000001', + 'path': '/mhr/api/v1/registrations/020000', + 'createDateTime': '2021-06-03T22:58:45+00:00', + 'registeringParty': 'Bank of British Columbia', + 'inUserList': False +} +TEST_VALID_MINIMUM = { + 'mhrNumber': '020000', + 'statusType': 'R', + 'path': '/mhr/api/v1/registrations/020000', + 'createDateTime': '2021-06-03T22:58:45+00:00' +} +TEST_INVALID_STATUS_TYPE = { + 'mhrNumber': '020000', + 'statusType': 'X', + 'path': '/mhr/api/v1/registrations/020000', + 'createDateTime': '2021-06-03T22:58:45+00:00' +} +TEST_INVALID_MHR_NUMBER = { + 'mhrNumber': '2020000', + 'statusType': 'R', + 'path': '/mhr/api/v1/registrations/020000', + 'createDateTime': '2021-06-03T22:58:45+00:00' +} +TEST_INVALID_MISSING_MHR_NUMBER = { + 'statusType': 'R', + 'path': '/mhr/api/v1/registrations/020000', + 'createDateTime': '2021-06-03T22:58:45+00:00' +} +TEST_INVALID_MISSING_STATUS = { + 'mhrNumber': '020000', + 'path': '/mhr/api/v1/registrations/020000', + 'createDateTime': '2021-06-03T22:58:45+00:00' +} +TEST_INVALID_MISSING_PATH = { + 'mhrNumber': '020000', + 'statusType': 'R', + 'createDateTime': '2021-06-03T22:58:45+00:00' +} +TEST_INVALID_MISSING_CREATE_TS = { + 'mhrNumber': '020000', + 'statusType': 'R', + 'path': '/mhr/api/v1/registrations/020000' +} +TEST_EMPTY_JSON = { +} + +# testdata pattern is ({description}, {is valid}, {data}) +TEST_DATA = [ + ('All valid', True, TEST_VALID_ALL), + ('Minimum valid', True, TEST_VALID_MINIMUM), + ('Invalid status type', False, TEST_INVALID_STATUS_TYPE), + ('Invalid mhr number length', False, TEST_INVALID_MHR_NUMBER), + ('Invalid missing mhr num', False, TEST_INVALID_MISSING_MHR_NUMBER), + ('Invalid missing status', False, TEST_INVALID_MISSING_STATUS), + ('Invalid missing path', False, TEST_INVALID_MISSING_PATH), + ('Invalid missing create_ts', False, TEST_INVALID_MISSING_CREATE_TS), + ('No settings', False, TEST_EMPTY_JSON) +] + + +@pytest.mark.parametrize('desc,valid,data', TEST_DATA) +def test_registration_summary(desc, valid, data): + """Assert that the schema is performing as expected for a registration summary.""" + is_valid, errors = validate(data, 'registrationSummary', 'mhr') + + if errors: + # print(errors) + for err in errors: + print(err.message) + + assert is_valid == valid diff --git a/tests/unit/ppr/test_vehicle_collateral.py b/tests/unit/ppr/test_vehicle_collateral.py index 0a80258..5c47ab7 100644 --- a/tests/unit/ppr/test_vehicle_collateral.py +++ b/tests/unit/ppr/test_vehicle_collateral.py @@ -47,6 +47,7 @@ ('MH', '002434', None, True, False, True), ('MH', '002434', None, True, True, False), ('MH', None, '123456', True, True, True), + ('MH', '002434', '123456', True, True, True), ('MH', None, None, False, True, True), ('MV', '242342342', None, True, True, True), ('MV', '242342342', None, False, False, True),