Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling changing registration purpose #2436

Merged
merged 31 commits into from
Jan 17, 2025

Conversation

andrea-williams
Copy link
Contributor

@andrea-williams andrea-williams commented Oct 31, 2024

Issue #2169

Note that this is only for the backend changes required. The frontend functionality to allow for changing registration purpose after the operation has already registered will follow in a subsequent PR.

  • added test_changing_registration_purposes.py file that tests for every possible scenario of changing registration purpose from A to B, for both operation types (LFO and SFO). Also accounts for whether the operation has a status of "Registered" (in which case no-longer-relevant database records will be archived) or not registered (in which case no-longer-relevant records are deleted).

@andrea-williams andrea-williams force-pushed the task/changing-reg-purpose/2169 branch 5 times, most recently from a862acb to 4735cb1 Compare November 7, 2024 00:30
@andrea-williams andrea-williams force-pushed the task/changing-reg-purpose/2169 branch from 4735cb1 to 40d36f0 Compare November 14, 2024 21:02
@andrea-williams andrea-williams force-pushed the task/changing-reg-purpose/2169 branch 3 times, most recently from ae804fb to 491151c Compare November 27, 2024 01:28
@andrea-williams andrea-williams force-pushed the task/changing-reg-purpose/2169 branch from 491151c to 4541316 Compare November 29, 2024 01:13
@andrea-williams andrea-williams force-pushed the task/changing-reg-purpose/2169 branch 4 times, most recently from ec92785 to b082037 Compare December 13, 2024 01:44
@andrea-williams andrea-williams force-pushed the task/changing-reg-purpose/2169 branch 2 times, most recently from 330dd49 to ddf6d7a Compare December 17, 2024 00:47
Copy link
Contributor

@BCerki BCerki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking on this monster, Andrea! If you want to go over anything, let me know--I ~think I followed things ok, but I may have made irrelevant comments where my brain couldn't keep up with yours

bc_obps/service/operation_service_v2.py Show resolved Hide resolved
bc_obps/service/operation_service_v2.py Outdated Show resolved Hide resolved
bc_obps/service/operation_service_v2.py Show resolved Hide resolved
bc_obps/service/operation_service_v2.py Outdated Show resolved Hide resolved
bc_obps/service/operation_service_v2.py Outdated Show resolved Hide resolved
assert self.operation.updated_by == self.user
assert self.operation.updated_at > self.operation.created_at

match original_purpose:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we go with a reorg like I suggested above (or a different, better one you come up with), I think we can avoid the match/case and the test will be easier to read

Comment on lines +640 to +622
if new_purpose == Operation.Purposes.OPTED_IN_OPERATION:
self._set_opted_in_operation_detail()
elif new_purpose == Operation.Purposes.NEW_ENTRANT_OPERATION:
self._set_new_entrant_info()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to confirm I understand how this would work in the app to make sure this test is representative. Say I'm on the operation page and click edit. I change the registration purpose, and at that point the opt-in/new entrant fields pop up. If I try to submit, I won't be able to until I fill in those fields. Correct? (Vs. how it is in the registration workflow where purpose and opt-in/new entrant are in separate steps and separate API calls.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's 2 possible scenarios. If registration_status == REGISTERED, this test mimics changing the purpose from the Operation Details page, in which case the new fields should display in the "Registration Information" section of the page and will need to be filled in before the user can click Save.

If registration_status == DRAFT, this test mimics a user going through the registration workflow, and at some point (before submitting their registration) going back to the first step to change the registration purpose, in which case a new section might be added to the flow, depending on which new purpose is chosen.

def _create_new_entrant_payload(self):
return {"date_of_first_shipment": "On or after April 1, 2024", "new_entrant_application": MOCK_DATA_URL}

def _prepare_test_data(self, registration_purpose, type):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced we need this function or _set_operation_information. I think we could achieve the same setup with baker recipes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we probably could achieve the same with baker recipes. In creating them this way, I was trying to (a) be more consistent with the structure of the other integration test (for operation registration) and (b) replicate the ordering of steps as they happen when a user is going through the registration workflow.

bc_obps/service/operation_service_v2.py Show resolved Hide resolved
@andrea-williams andrea-williams marked this pull request as ready for review January 6, 2025 16:32
@andrea-williams andrea-williams force-pushed the task/changing-reg-purpose/2169 branch 3 times, most recently from 4a36d22 to 34213f3 Compare January 10, 2025 02:12
@andrea-williams andrea-williams force-pushed the task/changing-reg-purpose/2169 branch 2 times, most recently from 01abcc9 to aa8f2eb Compare January 15, 2025 01:12
@@ -65,6 +66,7 @@ def set_up_valid_mock_operation(purpose: Operation.Purposes):
'utils.document', type=DocumentType.objects.get(name='new_entrant_application')
)
operation.documents.add(new_entrant_application)
operation.date_of_first_shipment = "On or after April 1, 2024"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need an operation.save() after this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, we don't even need the operation.save() I inserted a few lines below, since the function is returning the operation. The caller of the this function saves the operation.

approved_user_operator.user.user_guid, users_operation.id
)
users_operation.refresh_from_db()
# at the moment there's no easy way to tell whether a record has been deleted or archived, so not testing any further than
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way you did it in cas-registration/bc_obps/service/tests/test_document_service.py might work here too?

if registration_status == Operation.Statuses.REGISTERED:
            """if the registration has been completed, the document should have been archived"""
            b_map.refresh_from_db()
            assert b_map.archived_at is not None
            assert b_map.archived_by is not None
        elif registration_status == Operation.Statuses.DRAFT:
            """if the registration wasn't completed, the document should have been deleted"""
            with pytest.raises(Document.DoesNotExist):
                b_map.refresh_from_db()  # this should raise an exception because it no longer exists in the db

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done :)

@@ -235,7 +274,7 @@ def create_or_update_operation_v2(
operation.documents.add(*operation_documents)

if operation.registration_purpose == Operation.Purposes.OPTED_IN_OPERATION:
operation = cls.create_opted_in_operation_detail(user_guid, operation)
operation = cls.create_opted_in_operation_detail(user_guid, operation.id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm following correctly, handle_change_of_registration_purpose only archives/deletes data that's no longer needed for an old purpose. It doesn't add any of the new data--that adding happens in this create_or_update_operation_v2.

I think this function may be missing the update for operation detail (unless it's in another service somewhere; I only see create here).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment https://github.com/bcgov/cas-registration/pull/2436/files#r1917469882 - opted_in_operation detail is only ever being created here because we don't have any opt-in data available at this point - that gets called in a different function later in the workflow.

@@ -261,10 +300,10 @@ def register_operation_information(
)

if operation.registration_purpose == Operation.Purposes.OPTED_IN_OPERATION:
# TODO in ticket 2169 - replace this with create_or_update_-----
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This note makes me think the update should be here too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. I think the source of confusion is that when we're calling create_opted_in_operation_detail(), we only have the operation's id and know that it's RP is Opt-in. We don't have any data about the opt-in yet, so this is only creating a blank OptedInOperationDetail record in the database - it doesn't get populated with data until later (when update_opted_in_operation_detail gets called).

This is why create_opted_in_operation_detail is a completely separate function from update_opted_in_operation_detail, because the payload data is so different. (I know this is different behaviour from what we've typically done elsewhere in Reg, where create_or_update_x is just one function. But this strategy for opt-ins was written before this PR, and I think it's out of scope to refactor it now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, thanks!

Logic to handle the situation when an industry user changes the selected registration purpose (RP) for their operation.
Changing the RP can happen during or after submitting the operation's registration info.
Depending on what the old RP was, some operation data may need to be removed.
Depending on what the new RP is, some new operation data may need to be added.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending on what the new RP is, some new operation data may need to be added.--I only see things being archived/deleted, not added. If that's the intention, we could drop this line from the docstring

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair - the only data being "added" in switching the opt_in flag to false. I'll remove this line from the docstring.

Comment on lines 43 to 47
operation_information_payload = {
"boundary_map": MOCK_DATA_URL,
"process_flow_diagram": MOCK_DATA_URL,
"activities": [2, 3],
"naics_code_id": mock_naics_codes[1].id,
"secondary_naics_code_id": mock_naics_codes[2].id,
"name": self.operation.name,
"type": self.operation.type,
"registration_purpose": self.operation.registration_purpose,
"regulated_products": [1, 2],
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment is still relevant--this payload shouldn't be used to set up Potential Reporting, Reporting, or EIO because it contains things those purposes don't have (e.g. regulated products)

def _test_new_entrant_to_reporting(self):
"""
Tests operation registration data for situation where registration_purpose changes from New Entrant to Reporting Operation.
Registration data specific to new entrants (date of first shipment, new entrant application document) should be removed.
Copy link
Contributor

@BCerki BCerki Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

b don't see this was a note to self I forgot to remove, sorry for being confusing

@andrea-williams andrea-williams force-pushed the task/changing-reg-purpose/2169 branch 2 times, most recently from e25b3f3 to f0053e1 Compare January 16, 2025 01:14
Copy link
Contributor

@BCerki BCerki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work!
Re my flip-floppy thoughts on the test structure:

  • There are so many combinations of tos and froms that I'm not confident I noticed if a check for a particular field was missing. I commented when I saw the missing regulated products, but I don't know that I got every one, and as we try to maintain this test, that might continue to be an issue. The mock data wasn't set up completely correctly at first and everything still passed
  • this PR is huge and has taken a lot of time already, so maybe ^ is tech debt to kick down the road. I don't mind tackling it--I ~think I have a strategy that isn't too overwhelming

@andrea-williams
Copy link
Contributor Author

Amazing work! Re my flip-floppy thoughts on the test structure:

  • There are so many combinations of tos and froms that I'm not confident I noticed if a check for a particular field was missing. I commented when I saw the missing regulated products, but I don't know that I got every one, and as we try to maintain this test, that might continue to be an issue. The mock data wasn't set up completely correctly at first and everything still passed
  • this PR is huge and has taken a lot of time already, so maybe ^ is tech debt to kick down the road. I don't mind tackling it--I ~think I have a strategy that isn't too overwhelming

thanks Brianna! I greatly appreciate how much time and effort you put into reviewing this. You did a fantastic job catching my goofs!

…n multiples are required; fixed bug where reporting ops were also being marked as regulated erroneously
… of changing reg purpose - more refinement likely needed. Lots of failures
…O as original RP bc of doc count that's haunting me
@andrea-williams andrea-williams force-pushed the task/changing-reg-purpose/2169 branch from 903d941 to b4be968 Compare January 17, 2025 00:24
@andrea-williams andrea-williams merged commit a287ae4 into develop Jan 17, 2025
42 checks passed
@andrea-williams andrea-williams deleted the task/changing-reg-purpose/2169 branch January 17, 2025 00:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants