diff --git a/ppr-api/report-templates/template-parts/registration/securitiesActNotice.html b/ppr-api/report-templates/template-parts/registration/securitiesActNotice.html
index 17be91439..5a5c8ff59 100644
--- a/ppr-api/report-templates/template-parts/registration/securitiesActNotice.html
+++ b/ppr-api/report-templates/template-parts/registration/securitiesActNotice.html
@@ -56,7 +56,7 @@
{% for notice in change.addSecuritiesActNotices %}
{{ notice.registrationDescription|title }}
- {% if notice.amendNoticeId is defined%}CHANGED{% else %}ADDED{% endif %}
+ {% if notice.amendNoticeId is defined%}AMENDED{% else %}ADDED{% endif %}
{% if order.courtOrder %}Court Order {% else %}Security Commission Order{% endif %}
+
+ {% if order.courtOrder %}Court Order {% else %}Security Commission Order{% endif %}
+ {% if notice.amendNoticeId is defined and order.amendDeleted is defined %}
+ DELETED
+ {% elif notice.amendNoticeId is defined and order.amendOrderId is defined and order.unchanged is not defined %}
+ AMENDED
+ {% elif order.unchanged is not defined %}
+ ADDED
+ {% endif %}
+
{% if order.courtOrder %}Court Order {% else %}Security Commission Order{% endif %}
+ {% if order.courtOrder %}Court Order {% else %}Security Commission Order{% endif %} DELETED
{% if order.courtName is defined %}
diff --git a/ppr-api/report-templates/template-parts/search-result/securitiesActNotice.html b/ppr-api/report-templates/template-parts/search-result/securitiesActNotice.html
index 53862d549..8333ce3af 100644
--- a/ppr-api/report-templates/template-parts/search-result/securitiesActNotice.html
+++ b/ppr-api/report-templates/template-parts/search-result/securitiesActNotice.html
@@ -56,7 +56,7 @@
{% for notice in change.addSecuritiesActNotices %}
{{ notice.registrationDescription|title }}
- {% if notice.amendNoticeId is defined%}CHANGED{% else %}ADDED{% endif %}
+ {% if notice.amendNoticeId is defined%}AMENDED{% else %}ADDED{% endif %}
{% if notice.securitiesActOrders %}
{% for order in notice.securitiesActOrders %}
- {% if order.courtOrder %}Court Order {% else %}Security Commission Order{% endif %}
+
+ {% if order.courtOrder %}Court Order {% else %}Security Commission Order{% endif %}
+ {% if notice.amendNoticeId is defined and order.amendDeleted is defined %}
+ DELETED
+ {% elif notice.amendNoticeId is defined and order.amendOrderId is defined and order.unchanged is not defined %}
+ AMENDED
+ {% elif order.unchanged is not defined %}
+ ADDED
+ {% endif %}
+
{% if order.courtName is defined %}
@@ -120,7 +129,7 @@
{% if notice.securitiesActOrders %}
{% for order in notice.securitiesActOrders %}
- {% if order.courtOrder %}Court Order {% else %}Security Commission Order{% endif %}
+ {% if order.courtOrder %}Court Order {% else %}Security Commission Order{% endif %} DELETED
{% if order.courtName is defined %}
diff --git a/ppr-api/src/database/patch/15187-ppr-securities-act.sql b/ppr-api/src/database/patch/15187-ppr-securities-act.sql
index c287d1bbc..8f9a60cc9 100644
--- a/ppr-api/src/database/patch/15187-ppr-securities-act.sql
+++ b/ppr-api/src/database/patch/15187-ppr-securities-act.sql
@@ -47,6 +47,7 @@ CREATE TABLE public.securities_act_orders (
court_registry VARCHAR (64) NULL,
file_number VARCHAR (20) NULL,
effect_of_order VARCHAR (512) NULL,
+ previous_order_id INTEGER NULL,
FOREIGN KEY (securities_act_notice_id)
REFERENCES securities_act_notices (id),
FOREIGN KEY (registration_id)
@@ -57,4 +58,10 @@ CREATE TABLE public.securities_act_orders (
CREATE INDEX ix_sec_orders_sec_id ON public.securities_act_orders USING btree (securities_act_notice_id);
CREATE INDEX ix_sec_orders_registration_id ON public.securities_act_orders USING btree (registration_id);
CREATE INDEX ix_sec_orders_change_registration_id ON public.securities_act_orders USING btree (registration_id_end);
+
+INSERT INTO registration_types(registration_type, registration_type_cl, registration_desc, registration_act) VALUES
+('A1', 'AMENDMENT', 'AMENDMENT - NOTICE ADDED', 'SECURITIES ACT'),
+('A2', 'AMENDMENT', 'AMENDMENT - NOTICE REMOVEd', 'SECURITIES ACT'),
+('A3', 'AMENDMENT', 'AMENDMENT - NOTICE AMENDED', 'SECURITIES ACT')
+;
-- 15178 end release 1.2.5
diff --git a/ppr-api/src/ppr_api/models/securities_act_order.py b/ppr-api/src/ppr_api/models/securities_act_order.py
index 9efac8aaf..d1aae9fc7 100644
--- a/ppr-api/src/ppr_api/models/securities_act_order.py
+++ b/ppr-api/src/ppr_api/models/securities_act_order.py
@@ -29,6 +29,8 @@ class SecuritiesActOrder(db.Model):
file_number = db.mapped_column('file_number', db.String(20), nullable=True)
effect_of_order = db.mapped_column('effect_of_order', db.String(512), nullable=True)
registration_id_end = db.mapped_column('registration_id_end', db.Integer, nullable=True, index=True)
+ # For amendment distinguishing notice edit from remove/add
+ previous_order_id = db.mapped_column('previous_order_id', db.Integer, nullable=True)
# parent keys
registration_id = db.mapped_column('registration_id', db.Integer,
@@ -50,6 +52,7 @@ class SecuritiesActOrder(db.Model):
def json(self) -> dict:
"""Return the court_order as a json object."""
order = {
+ 'orderId': self.id,
'courtOrder': self.court_order_ind == 'Y'
}
if self.court_name:
@@ -62,6 +65,8 @@ def json(self) -> dict:
order['orderDate'] = format_ts(self.order_date)
if self.effect_of_order:
order['effectOfOrder'] = self.effect_of_order
+ if self.previous_order_id is not None:
+ order['amendOrderId'] = self.previous_order_id
return order
@classmethod
@@ -100,5 +105,6 @@ def create_from_json(json_data, registration_id: int, notice_id: int):
order.order_date = ts_from_date_iso_format(json_data['orderDate'])
if json_data.get('effectOfOrder'):
order.effect_of_order = json_data['effectOfOrder']
-
+ if json_data.get('amendOrderId'):
+ order.previous_order_id = json_data.get('amendOrderId')
return order
diff --git a/ppr-api/src/ppr_api/models/utils.py b/ppr-api/src/ppr_api/models/utils.py
index 2c5486c61..3055aef87 100644
--- a/ppr-api/src/ppr_api/models/utils.py
+++ b/ppr-api/src/ppr_api/models/utils.py
@@ -69,6 +69,9 @@
REG_TYPE_AMEND_PARIAL_DISCHARGE = 'AP'
REG_TYPE_AMEND_SP_TRANSFER = 'AS'
REG_TYPE_AMEND_SUBSTITUTION_COLLATERAL = 'AU'
+REG_TYPE_AMEND_SECURITIES_ADD = 'A1'
+REG_TYPE_AMEND_SECURITIES_DELETE = 'A2'
+REG_TYPE_AMEND_SECURITIES = 'A3'
SEARCH_MATCH_EXACT = 'EXACT'
SEARCH_MATCH_SIMILAR = 'SIMILAR'
@@ -802,14 +805,28 @@ def cleanup_amendment(json_data):
return json_data
-def amendment_change_type(json_data):
+def amendment_securities_change_type(json_data: dict) -> str:
+ """Try to assign a securities act notice specific amendment change type based on the request data."""
+ if json_data.get('addVehicleCollateral') or json_data.get('deleteVehicleCollateral') or \
+ json_data.get('addGeneralCollateral') or json_data.get('deleteGeneralCollateral') or \
+ json_data.get('addDebtors') or json_data.get('deleteDebtors'):
+ return REG_TYPE_AMEND
+ if json_data.get('addSecuritiesActNotices') and not json_data.get('deleteSecuritiesActNotices'):
+ return REG_TYPE_AMEND_SECURITIES_ADD
+ if not json_data.get('addSecuritiesActNotices') and json_data.get('deleteSecuritiesActNotices'):
+ return REG_TYPE_AMEND_SECURITIES_DELETE
+ return REG_TYPE_AMEND_SECURITIES
+
+
+def amendment_change_type(json_data: dict) -> str:
# pylint: disable=too-many-boolean-expressions
"""Try to assign a more specific amendment change type based on the request data."""
if 'courtOrderInformation' in json_data:
return REG_TYPE_AMEND_COURT
- if 'addTrustIndenture' in json_data or 'removeTrustIndenture' in json_data or \
- json_data.get('deleteSecuritiesActNotices') or json_data.get('addSecuritiesActNotices'):
+ if 'addTrustIndenture' in json_data or 'removeTrustIndenture' in json_data:
return REG_TYPE_AMEND
+ if json_data.get('deleteSecuritiesActNotices') or json_data.get('addSecuritiesActNotices'):
+ return amendment_securities_change_type(json_data)
change_type = json_data['changeType']
if 'addVehicleCollateral' not in json_data and 'deleteVehicleCollateral' not in json_data and \
'addGeneralCollateral' not in json_data and 'deleteGeneralCollateral' not in json_data:
diff --git a/ppr-api/src/ppr_api/reports/v2/report_utils.py b/ppr-api/src/ppr_api/reports/v2/report_utils.py
index e17484fba..e73d62340 100755
--- a/ppr-api/src/ppr_api/reports/v2/report_utils.py
+++ b/ppr-api/src/ppr_api/reports/v2/report_utils.py
@@ -93,6 +93,9 @@
}
# Map post go-live amendment descriptions
TO_AMEND_TYPE_DESCRIPTION = {
+ 'A1': 'Amendment - Notice Added',
+ 'A2': 'Amendment - Notice Removed',
+ 'A3': 'Amendment - Notice Amended',
'AA': 'Amendment - Collateral Added',
'AM': 'Amendment',
'CO': 'Amendment - Court Order',
@@ -665,14 +668,57 @@ def set_notice_date_time(notice: dict):
order['orderDate'] = to_report_datetime(order['orderDate'], False)
+def is_order_unchanged(order1: dict, order2: dict) -> bool:
+ """Determine if 2 Securities Act Notice orders are the same."""
+ if order1['courtOrder'] != order2['courtOrder']:
+ return False
+ if order1.get('fileNumber') != order2.get('fileNumber') or order1.get('orderDate') != order2.get('orderDate'):
+ return False
+ if order1.get('courtOrder') and order2.get('courtOrder') and \
+ (order1.get('courtName') != order2.get('courtName') or
+ order1.get('courtRegistry') != order2.get('courtRegistry')):
+ return False
+ return (not order1.get('effectOfOrder') and not order2.get('effectOfOrder')) or \
+ (order1.get('effectOfOrder') == order2.get('effectOfOrder'))
+
+
+def set_modified_order(add_notice: dict, del_notice: dict):
+ """Conditionally set amended notice order unchanged flag."""
+ for add_order in add_notice.get('securitiesActOrders'):
+ if add_order.get('amendOrderId'):
+ for del_order in del_notice.get('securitiesActOrders'):
+ if del_order.get('orderId') and del_order.get('orderId') == add_order.get('amendOrderId') and \
+ is_order_unchanged(add_order, del_order):
+ # If identical mark as unchanged
+ add_order['unchanged'] = True
+ # Amended notice deleted orders added to new orders but marked as deleted.
+ merged_orders = []
+ for add_order in add_notice.get('securitiesActOrders'):
+ if add_order.get('amendOrderId'):
+ for del_order in del_notice.get('securitiesActOrders'):
+ if del_order.get('orderId') and del_order.get('orderId') != add_order.get('amendOrderId'):
+ order = copy.deepcopy(del_order)
+ order['amendDeleted'] = True
+ merged_orders.append(order)
+ if merged_orders:
+ for add_order in add_notice.get('securitiesActOrders'):
+ merged_orders.append(add_order)
+ add_notice['securitiesActOrders'] = merged_orders
+
+
def set_modified_notice(statement):
"""Conditionally set amendment deleted notice edited flag."""
if statement.get('deleteSecuritiesActNotices') and statement.get('addSecuritiesActNotices'):
for add_notice in statement['addSecuritiesActNotices']:
+ del_notice = None
for delete_notice in statement['deleteSecuritiesActNotices']:
if add_notice.get('reg_id') and delete_notice.get('reg_id') and \
add_notice['reg_id'] == delete_notice['reg_id'] and 'edit' not in delete_notice:
if add_notice.get('amendNoticeId', 0) > 0 and \
add_notice['amendNoticeId'] == delete_notice.get('noticeId'):
delete_notice['edit'] = True
+ del_notice = delete_notice
break
+ # Amend order check
+ if del_notice and del_notice.get('securitiesActOrders') and add_notice.get('securitiesActOrders'):
+ set_modified_order(add_notice, del_notice)
diff --git a/ppr-api/tests/unit/api/test_user_profile.py b/ppr-api/tests/unit/api/test_user_profile.py
index 35ddbfafe..caeaa8ee8 100644
--- a/ppr-api/tests/unit/api/test_user_profile.py
+++ b/ppr-api/tests/unit/api/test_user_profile.py
@@ -20,6 +20,7 @@
import pytest
+from ppr_api.models import UserProfile
from ppr_api.services.authz import (
STAFF_ROLE,
PPR_ROLE,
@@ -101,6 +102,11 @@ def test_get_user_profile_agreement(session, client, jwt, desc, account_id, idp_
else:
headers = create_header_account(jwt, roles)
+ if agreement_required:
+ profile: UserProfile = UserProfile.find_by_id(int(idp_userid))
+ if profile and not profile.service_agreements.get('acceptAgreementRequired'):
+ profile.service_agreements['acceptAgreementRequired'] = True
+
# test
rv = client.get('/api/v1/user-profile', headers=headers)
# check
diff --git a/ppr-api/tests/unit/models/test_securities_act_order.py b/ppr-api/tests/unit/models/test_securities_act_order.py
index 6e043527a..aedc8e228 100644
--- a/ppr-api/tests/unit/models/test_securities_act_order.py
+++ b/ppr-api/tests/unit/models/test_securities_act_order.py
@@ -92,23 +92,28 @@ def test_securities_act_json(session):
registry = 'registry'
file = 'file'
effect = 'effect'
+ order_id = 10001
+ amend_id = 12345
order = SecuritiesActOrder(
- id=10001,
+ id=order_id,
securities_act_notice_id=10001,
court_order_ind='Y',
court_name=name,
order_date = now,
court_registry = registry,
file_number=file,
- effect_of_order=effect
+ effect_of_order=effect,
+ previous_order_id=amend_id
)
order_json = {
+ 'orderId': order_id,
'courtOrder': True,
'courtName': name,
'courtRegistry': registry,
'fileNumber': file,
'orderDate': model_utils.format_ts(now),
- 'effectOfOrder': effect
+ 'effectOfOrder': effect,
+ 'amendOrderId': amend_id
}
assert order.json == order_json
diff --git a/ppr-api/tests/unit/models/test_user_profile.py b/ppr-api/tests/unit/models/test_user_profile.py
index 2d496ff64..e99da4f46 100644
--- a/ppr-api/tests/unit/models/test_user_profile.py
+++ b/ppr-api/tests/unit/models/test_user_profile.py
@@ -18,6 +18,8 @@
"""
import pytest
+from flask import current_app
+
from ppr_api.models import User, UserProfile
@@ -283,6 +285,6 @@ def test_find_service_agreements(session, client, jwt, id, agreement_required):
if profile:
if agreement_required:
assert profile.service_agreements
- assert profile.service_agreements.get('acceptAgreementRequired')
+ assert 'acceptAgreementRequired' in profile.service_agreements
else:
assert not profile.service_agreements or not profile.service_agreements.get('acceptAgreementRequired')
diff --git a/ppr-api/tests/unit/models/test_utils.py b/ppr-api/tests/unit/models/test_utils.py
index e6e1c8506..de17391e7 100644
--- a/ppr-api/tests/unit/models/test_utils.py
+++ b/ppr-api/tests/unit/models/test_utils.py
@@ -23,6 +23,53 @@
from ppr_api.models import utils as model_utils, Registration, SearchRequest
+AMENDMENT_SE = {
+ 'baseRegistrationNumber': 'TEST0022',
+ 'debtorName': {
+ 'businessName': 'TEST 22 DEBTOR INC.'
+ },
+ 'authorizationReceived': True,
+ 'registeringParty': {
+ 'businessName': 'ABC SEARCHING COMPANY',
+ 'address': {
+ 'street': '222 SUMMER STREET',
+ 'city': 'VICTORIA',
+ 'region': 'BC',
+ 'country': 'CA',
+ 'postalCode': 'V8W 2V8'
+ },
+ 'emailAddress': 'bsmith@abc-search.com'
+ },
+ 'changeType': 'AM',
+ 'description': 'Test amendment.',
+ 'deleteSecuritiesActNotices': [
+ {
+ 'noticeId': 200000000,
+ 'securitiesActNoticeType': 'PRESERVATION'
+ }
+ ],
+ 'addSecuritiesActNotices': [
+ {
+ 'amendNoticeId': 200000000,
+ 'securitiesActNoticeType': 'PRESERVATION',
+ 'effectiveDateTime': '2024-04-22T06:59:59+00:00',
+ 'securitiesActOrders': [
+ {
+ 'courtOrder': True,
+ 'courtName': 'court name',
+ 'courtRegistry': 'registry',
+ 'fileNumber': 'filenumber',
+ 'orderDate': '2024-04-22T06:59:59+00:00',
+ 'effectOfOrder': 'Effect of order summary.'
+ }
+ ]
+ },
+ {
+ 'securitiesActNoticeType': 'PROCEEDINGS',
+ 'effectiveDateTime': '2024-05-13T06:59:59+00:00'
+ }
+ ]
+}
# testdata pattern is ({registration_ts}, {years}, {expiry_ts})
TEST_DATA_EXPIRY = [
('2021-08-31T00:00:01-07:00', 1, '2022-09-01T06:59:59+00:00'),
@@ -130,6 +177,15 @@
(model_utils.REG_TYPE_AMEND_PARIAL_DISCHARGE, False),
(model_utils.REG_TYPE_AMEND_SP_TRANSFER, False)
]
+# testdata pattern is ({change_type}, {add_notice}, {delete_notice}, {has_vc}, {has_gc}, {has_debtor})
+TEST_DATA_AMENDMENT_CHANGE_TYPE_SE = [
+ (model_utils.REG_TYPE_AMEND, True, True, True, False, False),
+ (model_utils.REG_TYPE_AMEND, True, True, False, True, False),
+ (model_utils.REG_TYPE_AMEND, True, True, False, False, True),
+ (model_utils.REG_TYPE_AMEND_SECURITIES_ADD, True, False, False, False, False),
+ (model_utils.REG_TYPE_AMEND_SECURITIES_DELETE, False, True, False, False, False),
+ (model_utils.REG_TYPE_AMEND_SECURITIES, True, True, False, False, False)
+]
# testdata pattern is ({desc}, {reg_num}, {doc_name})
TEST_DATA_DOC_STORAGE_NAME = [
('Financing', 'TEST0001', 'ppsalien-200000000-TEST0001.pdf'),
@@ -392,6 +448,28 @@ def test_amendment_change_type(change_type, is_general_collateral):
assert type == change_type
+@pytest.mark.parametrize('change_type,add_notice,delete_notice,has_vc,has_gc,has_debtor',
+ TEST_DATA_AMENDMENT_CHANGE_TYPE_SE)
+def test_amendment_change_type_se(change_type, add_notice, delete_notice, has_vc, has_gc, has_debtor):
+ """Assert that setting the securities act notice amendment change type works as expected."""
+ json_data = copy.deepcopy(AMENDMENT_SE)
+ if not add_notice:
+ del json_data['addSecuritiesActNotices']
+ if not delete_notice:
+ del json_data['deleteSecuritiesActNotices']
+ if has_vc:
+ json_data['addVehicleCollateral'] = copy.deepcopy(AMENDMENT_STATEMENT.get('addVehicleCollateral'))
+ json_data['deleteVehicleCollateral'] = copy.deepcopy(AMENDMENT_STATEMENT.get('deleteVehicleCollateral'))
+ if has_gc:
+ json_data['addGeneralCollateral'] = copy.deepcopy(AMENDMENT_STATEMENT.get('addGeneralCollateral'))
+ json_data['deleteGeneralCollateral'] = copy.deepcopy(AMENDMENT_STATEMENT.get('deleteGeneralCollateral'))
+ if has_debtor:
+ json_data['addDebtors'] = copy.deepcopy(AMENDMENT_STATEMENT.get('addDebtors'))
+
+ type = model_utils.amendment_change_type(json_data)
+ assert type == change_type
+
+
def test_cleanup_amendment():
"""Assert that removing empty lists/arrays from amendment data works as expected."""
json_data = copy.deepcopy(AMENDMENT_STATEMENT)