Skip to content

OBPIH-6585 Make code a required field when creating/editing location types#4968

Merged
awalkowiak merged 7 commits intodevelopfrom
bug/OBPIH-6585-location-type-code-non-null
Jan 14, 2025
Merged

OBPIH-6585 Make code a required field when creating/editing location types#4968
awalkowiak merged 7 commits intodevelopfrom
bug/OBPIH-6585-location-type-code-non-null

Conversation

@ewaterman
Copy link
Member

✨ Description of Change

A concise summary of what is being changed. Please provide enough context for reviewers to be able to understand the change and why it is necessary. If the issue/ticket already provides enough information, you can put "See ticket" as the description.

Link to GitHub issue or Jira ticket: https://pihemr.atlassian.net/browse/OBPIH-6585

Description: LocationType.locationTypeCode is currently a nullable field, but LocationDimension.locationTypeCode is a non-nullable field. If we ever have a location type with a null location type code, it causes column constraint failures when generating location dimensions for all locations and causes the whole action to fail.

350177317-0f0866ec-6f5b-4df8-b4a9-5864b35af124

This change is to make LocationType.locationTypeCode non-nullable.

Originally implemented in: #4755

@ewaterman ewaterman self-assigned this Dec 2, 2024
@github-actions github-actions bot added type: bug Addresses unintended behaviours of the app domain: frontend Changes or discussions relating to the frontend UI domain: backend Changes or discussions relating to the backend server flag: schema change Hilights a pull request that contains a change to the database schema labels Dec 2, 2024
@ewaterman
Copy link
Member Author

I verified that the following scenario works:

  • created a location type with a null code
  • apply my changes and run the migration
  • location type changes to DEFAULT and can still load correctly
  • edit the location type and changed the code to DEPOT
  • change applied successfully

</td>
<td valign="top" class="value ${hasErrors(bean: locationTypeInstance, field: 'description', 'errors')}">
<g:select name="locationTypeCode" class="chzn-select-deselect" from="${org.pih.warehouse.core.LocationTypeCode.list()}"
noSelection="['':'']"
Copy link
Member Author

@ewaterman ewaterman Dec 2, 2024

Choose a reason for hiding this comment

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

As a reminder, removing this line will default the selection to the first element in LocationTypeCode,list() (which is DEPOT)

@codecov
Copy link

codecov bot commented Dec 2, 2024

Codecov Report

Attention: Patch coverage is 33.33333% with 2 lines in your changes missing coverage. Please review.

Project coverage is 7.70%. Comparing base (6fa9a07) to head (bcfed7c).
Report is 188 commits behind head on develop.

Files with missing lines Patch % Lines
...g/pih/warehouse/core/LocationTypeController.groovy 0.00% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             develop   #4968      +/-   ##
============================================
+ Coverage       7.68%   7.70%   +0.01%     
- Complexity       833     842       +9     
============================================
  Files            610     610              
  Lines          42521   42521              
  Branches       10315   10315              
============================================
+ Hits            3268    3276       +8     
+ Misses         38773   38766       -7     
+ Partials         480     479       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@awalkowiak awalkowiak requested a review from jmiranda December 4, 2024 11:48
Copy link
Collaborator

@kchelstowski kchelstowski left a comment

Choose a reason for hiding this comment

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

I feel ok with the code, but I have a doubt if it's a good time to proceed with such change now. I'm worried about some existing data etc - I know you've added the default value, but I don't know if there are any edge cases where it would break something.

Copy link
Collaborator

@awalkowiak awalkowiak left a comment

Choose a reason for hiding this comment

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

I am not sure about these changes, on one hand these makes sense, but I am not sure about the DEFAULT location type code (Imho it could be just empty string). I'd like to get an opinion from @jmiranda. Plus this feels like something that does not to be released in 0.9.3? The immediate fix could be one of these:

  1. Manual data fix in db (not sure if this makes sense, but we could take a look what was the fix before in the https://pihemr.atlassian.net/browse/OBPIH-5256
  2. Make it nullable false, but blank true and allow empty strings there
  3. On the buildLocationDimension insert, to do a fallback to empty string of something to not break due to null
  4. Make nullable location type code on the location dimension for now.

@ewaterman ewaterman added the warn: do not merge Marks a pull request that is not yet ready to be merged label Dec 4, 2024
@ewaterman
Copy link
Member Author

marking as do not merge for now since we decided to resolve this one after we cut the 0.9.3 release

class="value ${hasErrors(bean: locationTypeInstance, field: 'description', 'errors')}">
<g:select name="locationTypeCode" class="chzn-select-deselect"
from="${org.pih.warehouse.core.LocationTypeCode.list()}"
noSelection="['': '']"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Removing this property means that the first one from the list is picked automatically or how is it working right now?

Copy link
Member Author

@ewaterman ewaterman Dec 5, 2024

Choose a reason for hiding this comment

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

yeah that's right. The first element of LocationTypeCode.list(), which is DEPOT. I can undo this change if we want, but not selecting a value throws us to an ugly error page

Copy link
Member

Choose a reason for hiding this comment

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

Thinking about this more, I would actually prefer the default to be empty and for the form submission to return and display a validation error for blank/null.

Can you post a screenshot of the ugly page (I assume this is the exception stacktrace) so I can figure out the best way to handle it?

Copy link
Member Author

Choose a reason for hiding this comment

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

image

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree it's probably better to default to empty and just handle the error better.

This is old gsp pages though so I don't know the best way to do that. Do we even have nice error handling at all for these pages? If it's not a simple fix, maybe it's fine to just leave it with the messy error given that the goal is to eventually migrate everything over to react... idk

Copy link
Collaborator

Choose a reason for hiding this comment

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

@ewaterman the reason for such error is that the data services throw validation exception when validation didn't pass.
It works the same way as the .save(failOnError: true) would work.
Regular .save() returns null if the validation didn't pass.
On GSP pages we usually tend to handle such cases like that:

if (x.validate() && x.save()) {
  render(view: ...)
  return
}
// If error occured
render(view: ...)

and then inside view:

<g:hasErrors bean="${x}">
            <div class="errors" role="alert" aria-label="error-message">
                <g:renderErrors bean="${x}" as="list" />
            </div>
</g:hasErrors>

and the errors are listed in user-friendly way.

Since data service's .save() throws en error, you'd have to wrap that in try/catch clause instead, but I'm not a fan of try/catch clause, because there were some inconsistencies in transaction rollback, but I do not remember now if it was Grails 1 or Grails 3 thing (would have to find our discussions from the past).

Copy link
Member Author

@ewaterman ewaterman Jan 10, 2025

Choose a reason for hiding this comment

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

Thanks for the detailed explanation. I looked into it and it's actually a really simple fix. It does have the frontend error processing that you suggested Kacper. The thing that was missing was the x.validate() step. Changing the code to the following works:

if (locationTypeInstance.validate() && locationTypeDataService.save(locationTypeInstance)) {
    flash.message = "${warehouse.message(code: 'default.updated.message', args: [...])}"
    redirect(action: "list", id: locationTypeInstance.id)
}
else {
    render(view: "edit", model: [locationTypeInstance: locationTypeInstance])
}

Screenshot from 2025-01-10 10-13-07

@ewaterman ewaterman removed the warn: do not merge Marks a pull request that is not yet ready to be merged label Dec 16, 2024
@ewaterman ewaterman changed the title OBPIH-5685 Make code a required field when creating/editing location types OBPIH-6585 Make code a required field when creating/editing location types Jan 2, 2025
@ewaterman
Copy link
Member Author

ewaterman commented Jan 10, 2025

As a refresher for the review (since it has been a while), the main change is to make LocationType.locationTypeCode non-nullable.

As a safety measure, I also migrate any existing nulls to use DEFAULT. There shouldn't be any location types with a null code (we don't have any in our environments) since it doesn't really make sense for it to be null, but the migration is there just in case any other implementations have it.

Artur suggested we use an empty/blank value instead of DEFAULT. I'm okay with this, but in the frontend, that would allow users to not select a value for location type code from the dropdown. Because all location types should have a code, I'm not sure this is the behaviour we want. I think it's better to explicitly fail to the user and force them to pick a code. Location types with a null/DEFAULT/blank value should need to be fixed because they can cause unexpected behaviour in the system, so I think we shouldn't allow creating new types without a code.

I suppose we could create a LocationTypeCommand object (right now the controller just serializes directly to the LocationType domain) that has locationTypeCode(nullable: false) and have the domain use locationTypeCode(nullable: false, blank:true) like Artur suggested. We'd still need the migration though.

Copy link
Member

@jmiranda jmiranda left a comment

Choose a reason for hiding this comment

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

This looks good to me. The only issue I found was that if somehow the location type code was empty string or some invalid value (i.e. INVALID), you'd get redirected to the exception page when attempting to manage location types.

image

Not sure how likely that scenario is so just something to consider if we encounter a support request.

@awalkowiak awalkowiak merged commit 89c6594 into develop Jan 14, 2025
8 checks passed
@awalkowiak awalkowiak deleted the bug/OBPIH-6585-location-type-code-non-null branch January 14, 2025 15:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain: backend Changes or discussions relating to the backend server domain: frontend Changes or discussions relating to the frontend UI flag: schema change Hilights a pull request that contains a change to the database schema type: bug Addresses unintended behaviours of the app

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants