From 35aa3b0bc317f49aecec3a18268021fde3eec6f9 Mon Sep 17 00:00:00 2001 From: Craig Reese <109101548+craigrva@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:46:57 -0500 Subject: [PATCH] Release R1.6.0 FY24Q3.6 (#22117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * APPEALS-44148: Add ruby_claim_evidence_api gem (#22059) * APPEALS-50758: Fix broken tests in spec/controllers/case_distribution_levers_controller_spec.rb (#22072) * update test data to fix tests * fix test data setup * fix dates in test setup * disable flaky jest test * APPEALS-49845: Hearing CAVC Appeals are not respecting CAVC affinity (#22043) * pass judge into base relation queries on hearing docket * update scopes to distribute CAVC hearing to original judge when within hearing window * APPEALS-49845: Add seed data (#22056) * add seed data * fix users seed spec * APPEALS-49555: Some AOD appeals are not being selected as priority by the distribution algorithm (#22067) * aod appeal with claimants person does not contain DOB * Addressed comments --------- Co-authored-by: Craig Reese <109101548+craigrva@users.noreply.github.com> * Merge feature/appeals-34320 into release branch (#22094) * ClayS/APPEALS-39107 (#21458) * add request issue modification button for non-admins * add tests covering the request issue modification button * appease rubocop overlord * update feature tests * change to inline style and absolute import * update feature test --------- Co-authored-by: Brandon Lee Dorner * JHoang/APPEALS-39445 (#21445) * added new dropdown actions for edit issues, restricted visibility to non vha admins * fix failing tests * update jest for new dropdown actions * added placeholder modal for request additional issue button * Replace relative import with absolute, rename variable to check for non vha admin * render new dropdown actions and button only for in progress tasks * revert previous changes, added new changes * fix typo in issuelist * typo again * remove extra empty line * fix jest tests and vha_hlr_sc rspec * address styling issues * more restrictions to dropdown/button visibility * remove unused comments --------- Co-authored-by: Jonathan Hoang * Pending Request Issues seeds, factories and query update (#21437) * migration and initial commit of the factory * changing approve status to status * Added active record associations on models, added factory attributes, added pending tasks on queue tab * adding AC-2 condition to get pending record response from pending_request_issue table * factory and seed for pending_request_issues * Added pending request issues count alias for sorting and serialization to Task query * adding issue_type_Count and task_type_count for pending tab * Added spec tests for vha business line and business line spec files, cleaned up the controller, modified issue_type_count query * fixing the spec failures and code climate issues * removed byebug * Fixing code climate issue and adding seed data * fixing the schema error * Revert "fixing the schema error" This reverts commit 73070faa40a5615c45ae9e7ec5a0bef74f419e9e. * skip association so that test passes * renaming the table to - issue_modification_request and corresponding changes to the model, factories * fixing spec failures and linter * fixing spec failures and linter * making sure pending tasks doesnt show up in in progress tab and modified the factory so that Claimant name appears * fixing the spec failure * removing coalesce and removing null: true * more PR feedbacks * adding fix to the PR comments * removing distinct * fixing the error in the query * Apply suggestions from code review Co-authored-by: Tyler Broyles <109369527+TylerBroyles@users.noreply.github.com> * removing limit as suggested in the pr * Adding evaluator to the factory and adding it to the seeds * Adding PaperTrail for change history stuff * adding schema * adding new column to the table * changed decider_decision_text to decider_note --------- Co-authored-by: almorbah Co-authored-by: Tyler Broyles <109369527+TylerBroyles@users.noreply.github.com> * SeanC/APPEALS-40669 | Creation of ‘Pending admin review’ section on Edit Issues Page (#21604) * Added fake data and rendering for it * made the fake data better * pending issues are being rendered * passed up user admin of org from backend * Added userIsOrgAdmin to the frontend * created admin and non fake data * determined fake data to use based on userIsOrgAdmin * got the issues to render * Created a new IssueModificationList component * updated the issuemodification and row to work with the lists * updated the fake data and the issues container * removed some code for getting the user info * updated IssueModificationRequest to make wireframe * Updated row and list to work with the new request * updated the fake data * added propTypes to IssuesModificationList * cleaned up some lint in addissues * added Prop types to request * added key to list * improved row * improved the row logic * added some space to the list * refactored the layout for the request * added text to the COPY * slight change to fake data * refactored the row * got sorting working * added id to map of list * updated formating functions for modificationIssueRequests * updated the request to work with the formated data * removed some console logs in row * updated addIssues to format the fake data * updated request to work with the serializer * removed logs * updated fake data and formatter * removed unneed code * removed unneed code * removed unneed code * Rename IssueModificationRow.jsx to issueModificationRow.jsx * removed unneed code and renamed a couple things * Slight change to request * removed some comments * added some data for the jest test * got some of the jest tests working * fixed a typo in request * updated the prop for the tests * fixed the broken test and added more for list * Fixed the fake data and removed unneed code * removed unneed coded * changed the html in the request to better match the design * added css rule for new class * fixed an typo in COPY * similified some logic in row * added logic to not create the pending section if it is null * cleaned up some lint in intake.scss * updated the fake data to better match the wireframes * added divider inbetween requests * formatted the dates on the request --------- Co-authored-by: Clay Sheppard * TYLERB/APPEALS-39106: Creation of Pending tab (#21455) * Initial commit to add the pending tab to the vha business line decision review queue. * Updated existing tests and added new ones for the pending tab. * Added tab task counts to the decision review queue. * Adjusted variable names to match up with the feature branch. Made a column change to the create_issue_modification_request migration file. Added in methods to serialize the issue_modification_requests. Added pending_issue_modification_requests to the decision review serializer. * Updated schema. * Added a serialzer and related javascript and redux methods to place issue modification requests into the frontend. * Updated tests to work with new issue modification request factories. * Added a couple more test scenarios for the decision review controller spec file and changed the FactoryBot.create methods to create(). * Removed extra copies of the pending tab mappings and if statements from the decision reviews controller that happened due to the feature merge. * Updated ReviewPage jest test snapshots. Updated and added more tests to the NonCompTabs jest test for the new pending tasks tab. Fixed an issue where the TaskTableTab was added an empty hash to the columns as a placeholder for the pending requests column instead of not adding any additional columns. * Added a few constant variables to copy.json and queue config and removed todo statements. * Fixed serializer tests and Fixed a constant name. * Renamed some javascript variables to match the serializer. * Fixed more broken tests. * Updated the pending tasks query to show the correct amount of pending issues instead of an incorrect count. Added the pendingRequests column to the SORT_COLUMN_MAPPINGS in the decision reviews controller so that the user can sort by the new pending requests column via the controller. Added tests to cover these scenarios. * Made some layout and css adjustments to the search bar and tab description for the decision review queue. * Added padding to the bottom of the new search box and description div to create some space between ui elements. Changed the tab titles in the decision review queue to be title case for all words instead of only the first word. --------- Co-authored-by: Brandon Lee Dorner * Appeals-40989 - Inclusion of required Decision Date Banner on Add Issues (#21588) * APPEALS-40989: Adding functionality to check if user is vhaAdmin and task is in progress then display Banner and make decision date required. * Fixing spec failures, adding new model spec, new task factory to support spec * fixing linter issues in spec * Adding storybook and fixing codeclimate complain * fixing PR comments and adding banner to unidendified modal * removing local font sizing * fixing linter issue * APPEALS-39446 - Modal creation – modification, removal, withdrawal, request additional issue [Non-Admin] (#21681) * WIP components TODO: validation/errors, redux * add some error messages and the error schema for the addition modal * add missing data error messages for the rest of the modals * add test coverage for issue modification request frontend errors * disable submit button until form is dirty * remove currentIssue from request additional issue modal * DRY out these modals * clean up imports and some formatting * WIP stuck the issue modification requests into redux * add requested additional issues to the pending review section * get benefit type from redux * add test covering modal submission * remove unnecessary expectation * move a line to read better * linting fixes and remove unneeded code * update test * really fix this test * try to fix the add isues page * fix ambiguous click in spec * add storybook for modals * update snapshot * update capitalization in reviews spec * destructure modal props * more destructuring * use full name and css id for requestor * import less lodash * fix some more capitalization * remove old comment * Update client/app/intakeEdit/components/RequestCommonComponents/RequestIssueFormWrapper.jsx Co-authored-by: Tyler Broyles <109369527+TylerBroyles@users.noreply.github.com> * Update client/app/intake/components/IssueModificationRequest.jsx Co-authored-by: Tyler Broyles <109369527+TylerBroyles@users.noreply.github.com> * prevent future dates in issue modification requests * format decision date in current issue section * Prior decision date -> Decision date --------- Co-authored-by: Prajwal Amatya <122557351+pamatyatake2@users.noreply.github.com> Co-authored-by: Tyler Broyles <109369527+TylerBroyles@users.noreply.github.com> * TYLERB/APPEALS-39447: Display of banner on Edit Issues page – issues with pending requests (#21695) * Initial commit. Added the PendingIssueModificationRequestsBanner. Added the connection between the serialized pending issue modification requests to the ui in the front end EditAddIssues page. Refactored the issueModificationRow, IssueModificationList, and IssueModificationRequest components. Changed the request_type enumeration to be lowercased to match the key value and changed the database schema, migration, and factory to match up with the new enumeration value. * Added withdrawal_date to the serializer and redux store for issue modifications. Renamed a constant variable from body to message. Swapped a groupBy function to the lodash version since it was causing capyabara to fail for the feature test. Added a feature test for the banner. Also added a some helper functions and feature test checks for the issue modification requests when pulling data from the actual database objects instead of mocked data. * Updated jest test. * Added a backup description to the request issue in the IssueModificationRequest.jsx file so it will work for request issues being moved to the section via the ui. * Changed an rspec matcher to fix code climate issue. * Removed two junk console output files that were erroneously created. * Made changes to the issue modification ui to match the feature branch changes and renamed the redux key to always use pendingIssueModificationRequests. * Added a new redux store key for the originalPendingRequests in order to move them around. Reworked how the issues were being removed from the issues section when they are associated to an existing or new pending request. * Cleaned up old issue modification request redux code. * Reverted a change to the intake redux store since the objects are added via reference instead of an object clone. * Fixed an issue where having empty pendingIssueModificationRequ ests was causing a javascript error. Removed some todo comments and commented code. * Removed another todo comment. * Removed the pending requests banner from the cancel edit issues page. * Changed the issue modification seeds file to use the correct values for the request_type attribute based on the enumeration value change to always use lowercase values. Updated a variable name in javascript to be more descriptive. * Updated the RequestIssueFormWrapper component so that withdrawal and removal requests would behave in the same way as modification of existing issue requests. Fixed a bug where the decision date was being set to undefined or null for removal or withdrawal issue modification requests instead of taking the decision date from the original issue. * Removed n+1 bullet warnings from the decision_review serialization process for pending_issue_modification_requests. * APPEALS-45242 (partial) (#21759) * add a doubleArrow option to SearchableDropdown * overriden -> replaced * JHoang/APPEALS-40672 (#21756) * Initial commit. Added the PendingIssueModificationRequestsBanner. Added the connection between the serialized pending issue modification requests to the ui in the front end EditAddIssues page. Refactored the issueModificationRow, IssueModificationList, and IssueModificationRequest components. Changed the request_type enumeration to be lowercased to match the key value and changed the database schema, migration, and factory to match up with the new enumeration value. * Added withdrawal_date to the serializer and redux store for issue modifications. Renamed a constant variable from body to message. Swapped a groupBy function to the lodash version since it was causing capyabara to fail for the feature test. Added a feature test for the banner. Also added a some helper functions and feature test checks for the issue modification requests when pulling data from the actual database objects instead of mocked data. * Updated jest test. * Added a backup description to the request issue in the IssueModificationRequest.jsx file so it will work for request issues being moved to the section via the ui. * Changed an rspec matcher to fix code climate issue. * Removed two junk console output files that were erroneously created. * Made changes to the issue modification ui to match the feature branch changes and renamed the redux key to always use pendingIssueModificationRequests. * Added a new redux store key for the originalPendingRequests in order to move them around. Reworked how the issues were being removed from the issues section when they are associated to an existing or new pending request. * Cleaned up old issue modification request redux code. * Reverted a change to the intake redux store since the objects are added via reference instead of an object clone. * Fixed an issue where having empty pendingIssueModificationRequ ests was causing a javascript error. Removed some todo comments and commented code. * Removed another todo comment. * Removed the pending requests banner from the cancel edit issues page. * Changed the issue modification seeds file to use the correct values for the request_type attribute based on the enumeration value change to always use lowercase values. Updated a variable name in javascript to be more descriptive. * Added modal to request cancellation of an existing request modification * fix lint and failing jest * conditional rendering in cancelpendingrequestissue modal * fix decision date and withdrawal dates not showing correctly when requesting modification * fix mocked props for CancelPendingRequestIssueModal.test.js * revert date changes, fix issue description display * Updated the RequestIssueFormWrapper component so that withdrawal and removal requests would behave in the same way as modification of existing issue requests. Fixed a bug where the decision date was being set to undefined or null for removal or withdrawal issue modification requests instead of taking the decision date from the original issue. * added space between current issue and pending issue request * refactor cancelpendingrequestissuemodal structure * remove temp dropdown button --------- Co-authored-by: = Co-authored-by: Jonathan Hoang * Al/appeals 45834 (#21641) * Added non admin issue modification request logic * added finial touches on NON::AdminModificationRequestsUpdater class * Added logic to make sure that the user is an admin or non-admin who belongs to Vha organization * Added some Rspec tests for `NonAdmin::IssueModificationRequestsUpdater` and cleaned up Class * Added controller spec tests for SupplementalClaimsController#update HigherLevelReviewsController#update * Code clean up * Fixing lining errors * code clean up * Added code to fix some failing rspec tests * fixed linting errors * Ensure backend validation – only one request per issue If an issue already has a request and another is submitted, an error is thrown * rebased off latest feature branch and downcased request_type and status params * Added request_issue_id param to account for existing request_issues in situations when request_type is other than addition. Adjusted process_modification? method * Added changes based on PR feedback * added a shared example block to dry up code * more feedback * changed name file structure * Needed to re-handle validation errors * Pamatya/appeals 40671- adding Select action dropdown to the Admin section (#21788) * Adding props and searchable dropdown to meet ac * fixing linter, and adding test * added storybook for issue modification row and issue section row * fixing the values in the popup * fixing the Removal and withdrawal modal to behave similar to modification modal * making changes to the code to fix the bug * fixing spec, linter and jest failures * missing schema file * changing the Onclick to take object instead of the index or identifier * removing unused code * code cleanup * J hoang/appeals 40987 (#21889) * move issue modification request actions to new file, created new confirm issue modification change modal * fixed some code climate issues * some changes from review * fix jest * added new action to update pending issue request * maybe fix tests? * revert pending admin review display * change pending admin review display to active pending issues only * fix pending admin display * consistent parameter placement and added an extra check for requested issues display * fix all failing tests * fix movetopendingreview action call breaking rspec * fix cancel buttons on confirm modal modification --------- Co-authored-by: Jonathan Hoang * APPEALS-46705: Addition of SearchableDropdown to IssueList (#21752) * change issue action selector component and appearance * fix padding * fix linting error * fix frontend tests * fix list rendering bug * wip fix one type of failure * fix a couple more kinds of failure * fix tests in ama_queue_workflow_spec * fix a couple tests * another one * fix dropdown helpers to work if something was already selected * fix test in edit_ep_claim_labels_spec * fix issue modification request specs * more tests * update more tests * whac a mole * remove comment * fix padding * remove comment and whitespace * make specs consistent * SeanC/APPEALS-40670 | Update actions and pending request modal on Edit Issues Page – issues with pending requests [Non-Admin] (#21857) * got the options actions working * hooked up the cancel action * added some styling for drop down * changed the wording of the dropdown actions * added new onClick action, added pending obj to state and cleared it * passed the onClick to Row and List * added onClick and useSelector to Request * added new redux action * removed comment * added edit redux action * fixed an issue from merge in addIssues * updated the options to work with non admin actions and readOnly * removed unneed styles * removed comment * changed modal title to change based on pendingIssueModificationRequests * removed redundant code * updated action and reducer to work with other code * updated name of action on parent component * updated form wrapper to work with new action * fixed a failing spec test * Added tests for action options for non and admin users * refactored the props for the test for IssueModificationList * slight change to the test * add new test in issue_modification_request spec * added logic in Request for the text to change slightly * fixed a failing test * fixed an error with the form wrapper * fixed a few issues from the merge * fixed failing test * fixed an issue from the merge * changed I back to i for issueModificationRow * refactored options to a const in Request * removed added comma in constants * renamed const in FormWrapper * removed no longer needed props in IssueModificationListProps * removed setting the index when reviewing a modification request * fixed a date formatting issue * created const for pendingIssueModificationRequest * Fixed issue with incorrectly changing admin modal title * cleaned up some lint * cleaned up more lint * fixed an import issue * removed conditional for the label text * fixed a failing jest test * fixed failing rspec * removed comment in issue_modification_request_spec * APPEALS-47866 (#21916) * UX changes for modals red buttons -> blue buttons text wraps around icon copy updates * rspec updates * update snapshots * add a storybook for modals with icons * refactor storybook * remove class * switch to constants * remove unnecessary props * fix the AddIssues storybook * tinkering * update snapshots again * Pamatya/appeals 40997 v3 (#21926) * move issue modification request actions to new file, created new confirm issue modification change modal * fixed some code climate issues * some changes from review * fix jest * added new action to update pending issue request * maybe fix tests? * revert pending admin review display * change pending admin review display to active pending issues only * fix pending admin display * consistent parameter placement and added an extra check for requested issues display * fix all failing tests * fix movetopendingreview action call breaking rspec * fix cancel buttons on confirm modal modification * initial push * renaming component and making the remove original issue button work * fixing issues related with closing the modal and addissues page getting prerendered * fixing spec failure * fixing spec and linter issues * adding spec test for approval and rejection * new branch withdrawal date * fixing bug and fixing the jest failure * addressing comments * fixing spec and linter failure * code clean and consistency between two modals * adding validation to the spec * fixing the spec failure * fixing spacing and spec * fixing linter --------- Co-authored-by: Jonathan Hoang * Update schema.rb Fix error in previous merge conflict attempt. * Update seeds.rb Fix error in conflict resolution * TYLERB/APPEALS-40985: Frontend Submission of Requested Issues/Pending Admin Review Section (#21912) * Initial commit. Altered an existing model validation for issue modification requests and added a new validation. Added a formatter to prepare the issue modification requests for form submission and altered the button text for vha to be save instead of establish if there are pending issue modificaiton requests in the redux store. * Added the redirection code for claim reviews that have active pending issue modification requests. Also added the non admin issue modification success banner and refactored the existing flash banner code for other claim review types to make them easier to modify in the future. * Fixed code climate issue. * Renamed a function parameter in RequestIssueFormWrapper to make it more clear on what it is actually using. Updated logic to use a property insted of the form data. * Refactored how the claim review controller was building flash messaging to make it easier to customize it for vha claim reviews. * Added a new selectors file with a selector to only get openPendingModification requests which are pending modification requests that are assigned. Changed the selector in the PendingIssueModificationRequestBanner to the new selector. * Moved the open pending issue modification requests selector to the intake selector. Imported it and used it in the add issues page. * Fixed an issue where the decision date was not added as the correct string format to the issue modification redux store which was causing it to fail to save later after form submission. Expanded the feature test for non admin to include submitting the form and verifying the success banner and issue modification request data. * Added one more additional check to the feature test. * Added the open issue modification requests selector the save btton text for the edit issues page. * Made changes to the CancelPendingRequests modal to work with a new reducer. Added edited and cancelled pending requests to the formatIssueModificationRequestSubmissionData function. * Added an edited boolean attribute to the form data for modification type modals for pending requests for an easy way to determine if a issue modification request has been edited without changing the status. * Removed max width from non comp description text. * Fixed admin messaging when there are pending issue modification requests remaining on the claim review. * Added all the remaining frontend code and logic to make the issue modification form submission work. Fixed an issue where withdrawal date was not working correctly with the existing withdrawal process. * Refactored the claim review controller logic to work with the non admin and admin updates to issue modification requests. Added methods into issue modification request for admin updates. Updated validations. Refactored the non_admin_updater to work for both admin and non admin workflows. Added some fallback error handling for issue modification updates. * Removed unused import. * Updated the RequestIssueStatus component option value from rejected to denied to matchup with the enum field on the issue_modification_request model. * Fixed two code climate issues. Rewrote the issue modification request factories to fix the seed data. * Removed some lines from RequestIssueFormWrapper that I don't think were neccessary. Removed some todos. * Fixed a couple of failing specs. * Added a new feature test spec file that Praj created. * Added code to make the associations for request issues to issue modification requests through the UI work correctly in the request_issues_update model for additions and modifications since it is creating brand new request issues instead of using existing records in the database. * Renamed non_admin_updater_spec file and fixed tests. * Code climate fix. * Updated the mocked data controller tests. * Renamed the NonAdminUpdater and all related files to Updater. * Fixed a bug where the confirm pending request issue modal was not properly setting up the request issue by using the old request issue id that the modification request was associated to. Fixed a console warning in the RequestIssueStatus component. * Fixed spec failures due to changing banner text for editing vha claims. * Fixed an issue where the openPendingModificationRequests selector was causing a console error for legacy appeals due to different initialization of the redux store. Removed the no decision date banner for legacy appeals since it was never intended although it shouldn't happen. * Fixed jest test for CancelPendingRequestIssueModal where the property name had changed. * Added admin process testing to the updater_spec.rb service class for issue modification requests. Added errors to caseflow error.rb and added a constant to copy.json. * Removed todo statements. * Updated a modal snapshot. * Fixed merge conflicts that didn't get resolved. * Added an addition check for the wording to be correct for the issues update banner in add issues to properly reflect the wording of the save button at the bottom of the page depending on pending issue modification requests. Changed the wording on a success banner from established to edited that was incorrect. Added a different success banner for a vha claim review when it still has pending issue modification requests after an admin has only actioned some of them. * Updated the NonRatingIssueRequestModal decision date logic to prevent a non vha user from adding an issue without a decision date to a claim that was already in progress. * Fixed spec failures related to the banner text changes. * Added a banner and block the save of the page if the user is about to close a claim via a removal or withdrawal while the claim still has a pending addition issue modification request on it. Added feature test for this and uncommented some feature test code that shouldn't have been commented out. Added a way to make the content column span two columns in the add issues page table for styling the banner. * Moved the new banner check into the edit page block to fix tests. * CSS text change for the alert banner. * text change and text title change * Removed the established vha text variable in the claim review controller since it isn't being used anymore. Fixed a linting error. * test fix for alert title change --------- Co-authored-by: almorbah <149511814+almorbah@users.noreply.github.com> Co-authored-by: Prajwal Amatya Co-authored-by: Robert Travis Pierce * Initial commit. Added a transaction wrapper around the update_admin_request updater service method to prevent partial processing of requests if an error occured during any of the processing. Added an if check to the claim review controller to make sure that the request issues update class can be processed before processing any of the approval issue modification requests to avoid processing the requests without modifying the request issues that are currently on the claim. * Added in code climate change and seed data change to match master. * Added a public method for request issues update to check for p ossible errors before running the perform method. Refactored the controller logic to fix test failures. * Added approval back it got accidently removed. Removed some spacing in addissues.jsx. * Fixed a few flaky tests due to time errors. * Pamatya/appeals 49849 (#22057) * adding banner for both admin and non-admin and test * typo correction * removing commented out codes and adding a space between lines * removing props from the syntax * changing let to const --------- Co-authored-by: Clay Sheppard Co-authored-by: Brandon Lee Dorner Co-authored-by: jonathanh-va <111081469+jonathanh-va@users.noreply.github.com> Co-authored-by: Jonathan Hoang Co-authored-by: Prajwal Amatya <122557351+pamatyatake2@users.noreply.github.com> Co-authored-by: almorbah Co-authored-by: Tyler Broyles <109369527+TylerBroyles@users.noreply.github.com> Co-authored-by: Brandon Dorner Co-authored-by: Sean Craig <110493538+seancva@users.noreply.github.com> Co-authored-by: = Co-authored-by: almorbah <149511814+almorbah@users.noreply.github.com> Co-authored-by: Robert Travis Pierce Co-authored-by: Prajwal Amatya * updated dispatch mailer email address to Decisions instead of Hearings (#22095) Co-authored-by: Ron Wabukenda <130374706+ronwabVa@users.noreply.github.com> * APPEALS-45631 Add and fix address (#21800) * APPEALS-45631 Add and fix address * empty commit * empty commit * fix/add RO id * changed id from SS to GB --------- Co-authored-by: Ron Wabukenda <130374706+ronwabVa@users.noreply.github.com> * Prodtest/appeals-36234-appeals-44031 (#22109) * APPEALS-36339 (#21436) * Updated to remove obsolete levers of ACD Disable Legacy Distributions and ACD Disable Non-priority Distributions * Fixed redundant linting issue * Fixed empty line linting issue * Changed dockerfile to install node through NVM * Update env.sh with node 14.20 path * Removed unused node env * Update Dockerfile Removed unused node env variable * Removed unused node env * mbeard/APPEALS-44379 (#21451) * init commit * new questions about method * method for ready_appeals_from_levers 3rd iteration * switched to conditional * updates test and constants file * adds testing scenarios for edge cases * fixes test * adds constants to top of file --------- Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> * APPEALS-44417 Seeds for Docket Lever Demo (#21534) Co-authored-by: Christopher Detlef <> * APPEALS-36345-updated (#21537) * Refactored exclusion table * Fixed ordering issue and testing * mbeard/APPEALS-44379 (#21530) * init commit * new questions about method * method for ready_appeals_from_levers 3rd iteration * switched to conditional * updates test and constants file * adds testing scenarios for edge cases * fixes test * adds constants to top of file * first new commit with new args * updates methods and test query * updates age_of_oldest methods params * cleans up method removes args and updates tests, fixes linting --------- Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> * APPEALS-44346 Demo Docket Goal Lever Test Seed Data (#21524) Co-authored-by: Christopher Detlef <> * Chrisbdetlef/appeals 40705 (#21535) * Chris backend Work * APPEALS-44441. Added initial changes for individual seed * WIP * APPEALS-44441. Fixed the table css * APPEALS-44441. Added Custom and Scenario Seed components and jest tests * APPEALS-44441. Fix ScenarioSeeds jest test * APPEALS-44441. Fix CustomeSeeds Jest test * init commit * fixes linting issues * capybara test init * APPEALS-44441. Backend Integration API changes * APPEALS-44441_1. Matched the constant keys in the backend * APPEALS-44441_1. Update the param to match the backend and fixed spec * APPEALS-44441. lint fixes * APPEALS-44441. linting fixes * sharsha/APPEALS-44441. fixed the route and tests * Change route * Change variables to match front and back end * CustomSeed Jest test fix * Fix issues * Fix rubocop issues * Use existing method in the controller --------- Co-authored-by: Christopher Detlef <> Co-authored-by: SHarshain Co-authored-by: Michael Beard Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> * Sharsha/appeals 45531 (#21566) * Fixed rspec failures on constants * APPEALS-45531. Remove dead code --------- Co-authored-by: SHarshain * Updated lever history to handle null unit values from docket levers (#21567) Co-authored-by: 631966 * Sharsha/appeals 45531_1 (#21573) * APPEALS-45531. Add the controller which is used in the route * APPEALS-45531. Fix lint issue * Remove access check for this iteration * APPEALS-45531. Fix lint issue in controller --------- Co-authored-by: SHarshain Co-authored-by: Christopher Detlef <> Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> * Sharsha/appeals 45531 1 (#21609) * APPEALS-45531. Add the controller which is used in the route * APPEALS-45531. Fix lint issue * Remove access check for this iteration * APPEALS-45531. Fix lint issue in controller * TEST FOR FIX * MORE TESTING * Fixed rspec issues --------- Co-authored-by: SHarshain Co-authored-by: Christopher Detlef <> Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> * APPEALS-45502. Organize route and fix the controller (#21595) Co-authored-by: SHarshain Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> * Ricky/APPEALS-36345.fixes (#21612) * Updated lever history to handle null unit values from docket levers * Updated member view of exclusion table with proper text display and fixed missing css * Updated unit test and test data to test rendering of exclusionTable --------- Co-authored-by: 631966 * ricky/APPEALS-44053 (#21587) * init commit, adds conditional to check for docket_type ama to method, fixes json constants to snakecase * puts statements testing * updates seeds for evidence_submission, adds method to hearing_request_docket.rb and dist_concern.rb * updated appeals dsit * final fix for PR * updates spec to reflect changes in hearing_request_docket * uncomments seeds * Ricky/appeals 43523 (#21649) * Added Assignment Queue link to Switch Users test page * Updated controller to validate role and redirect * Updated error information * Updated rspec tests --------- Co-authored-by: 631068 * APPEALS-45898. Updated the lever_group_order values (#21639) * APPEALS-45898. Updated the lever_group_order values * APPEALS-45898. Updated order of the evidence submission priority and non-priority --------- Co-authored-by: SHarshain * mbeard/APPEALS-40646 (#21645) * Init commit * adds methods and useffect first pass * fixes isIdle warning * removes important from scss * refined handleToggleChange method * updates font color for h4 * adds keys to the td and fixed proptype for loadAcdExcludeFromAffinity in casedistributionapp * Chrisbdetlef/appeals 43117.cleanup (#21671) * APPEALS-43421: Attorney Selection Sticking on Dropdown after Assignment (#21401) * redo init commit * updated imp. logic * attorney widget fix --------- Co-authored-by: Calvin * Add ruby CE API Gem * remove correspondence changes from schema.rb (#21468) * Revert "Add ruby CE API Gem" (#21479) This reverts commit c78afe30620716d59d2ac31ad6eed71585d78a98. * Override SCT Bulk Assign Page task limit (#21465) * Override SCT Bulk Assign Queue 15 case limit & Adjust SCT attorney assign task action label * feature/APPEALS-35707-29633-29632 (prodtest) (#21485) * 🔀 Squash merge AlecK/APPEALS-35707 - Replace `database_cleaner` with `database_cleaner-active_record` * 🔀 Squash merge jcroteau/APPEALS-29632-fix-deprecation-action-view-base-instances * 🔀 Squash merge jcroteau/APPEALS-29633-fix-deprecation-warning-active_record-result-to_hash * feature/APPEALS-44871 Steps for installing node in the Caseflow demo environment (#21483) (#21484) * Changed dockerfile to install node through NVM * Update env.sh with node 14.20 path * Removed unused node env * Update Dockerfile Removed unused node env variable * Revert "feature/APPEALS-44871 Steps for installing node in the Caseflow demo …" (#21489) This reverts commit a6262001f9bedabca60598c82bfe1b803f0f16c7. * Sbashamoni/appeals 44871 node14 demo fixes (#21490) (#21495) * Changed dockerfile to install node through NVM * Update env.sh with node 14.20 path * Removed unused node env * Update Dockerfile Removed unused node env variable * Removed unused node env * add error rules to demo builds (#21496) (#21498) Co-authored-by: davis-dwayne <47563178+davis-dwayne@users.noreply.github.com> * APPEALS-43117 Add QA Users for testing * Fix rspecs * Fix issues with attorneys and judge teams * Fix org count --------- Co-authored-by: Isaiah Saucedo Co-authored-by: Calvin Co-authored-by: youfoundmanesh Co-authored-by: Craig Reese <109101548+craigrva@users.noreply.github.com> Co-authored-by: Robert Travis Pierce Co-authored-by: Jeremy Croteau Co-authored-by: sbashamoni <138054633+sbashamoni@users.noreply.github.com> Co-authored-by: davis-dwayne <47563178+davis-dwayne@users.noreply.github.com> Co-authored-by: Christopher Detlef <> * Minor fixes (#21694) * Minor fixes * Fix rspec tests and properly check for judge css id * Fix lint issue --------- Co-authored-by: Christopher Detlef <> * Fix Legacy Case issues (#21747) Co-authored-by: Christopher Detlef <> * APPEALS-46037. Fix padding in the lever history table (#21725) * APPEALS-46037. Fix padding in the lever history table * APPEALS-46037. Fix lint issues --------- Co-authored-by: SHarshain * Fix Lauren Roth issue (#21813) * Users with a VACOLS::Staff entry no longer get created with the default name of Lauren Roth Co-authored-by: Christopher Detlef <> * ricky/APPEALS-44044 (#21814) * first pass at legacy_docket method and spec * second iteration of legacy_docket and spec * adds method to age_of_oldest methods and updates test scenarios * Updated testing and expanded method missing logic * Updated legacy_docket_spec file and tests * Updated boolean logic, updated rspecs and factories * Updated rspec tests to include factories * updates docket_spec line 317 and factory for disable_ama_non_priority_direct_review --------- Co-authored-by: Michael Beard * updates ready_priority_nonpriority_appeals to public_send, updates test (#21844) * APPEALS-36333 first iteration of docket time goal and prior to goal (#21523) * APPEALS-36333 first iteration of docket time goal and prior to goal * APPEALS-36333 address pr comments and moved the logic to docket model * APPEALS-36333 Added specs for docket and hearing request docket models * refactored code and moved it to distribution scopes * APPEALS-36333 address pr comments and refactor code * APPEALS-43996 updated lever name in all the required files to fix spec failures * APPEALS-44000 revert hearing request docket model changes to keept it in sync with feature * APPEALS-44000 updated hearing request docket model specs * APPEALS-44000 fixed jest tests * APPEALS-44000 fixed broken rspecs * APPEALS-43996 fix rubocop warnings * APPEALS-43996 fix push priority job spec failures * APPEALS-43996 Updated case distribution lever and docker model and refactor specs * APPEALS-43996 added rake task to update case distribution lever item in db * APPEALS-43996 update docket model to handle the scenario when the lever being disabled by a user via the UI * APPEALS-43996 update section title * APPEALS-43996 revert rake task * APPEALS-43996 add new factories to case distribution lever and fix spec failures * APPEALS-45191. Added columns to the appeals ready to distribute query and made some tweaks (#21834) * APPEALS-45191. Added columns to the appeals ready to distribute query and made some tweaks * APPEALS-45191. Refactor and fix lint issues --------- Co-authored-by: SHarshain * refactor the logic and fix docket spec failures * changed the call times to 3 times * APPEALS-36333 fixed the docket time goal to check the existence of the item before using the public send to get the value --------- Co-authored-by: SHarshain <133917878+SHarshain@users.noreply.github.com> Co-authored-by: SHarshain Co-authored-by: 631966 * updated the seeds to align with the work completed * Updated Toggle Switch behavior when clicked while idle (#21874) * Csv research (#21892) * APPEALS-44911. Change the pure react components to functional components * APPEALS-44911. Redux implementation * APPEALS-44911. CSS changes for custom seed preview * APPEALS-44911. tweak css * csv and etc * CSS for buttons * jest tests for the reducer and action types * Jest test --------- Co-authored-by: SHarshain Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> * APPEALS-46057. CleanUP (#21914) * more jest tests * Disable scenario seeds * Lint fixes * APPEALS-46057. disable all scenario seeds * APPEALS-46057. Refactor the TestSeed wrapper to be a functional component and fixed jest test * APPEALS-46057. Jest job in GHA complaining on test --------- Co-authored-by: SHarshain * updates line of test to correctly build lever item (#21918) Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> * APPEALS-45191. Updated the query to return the date based on the calculation (#21928) * APPEALS-45191. Updated the query to return the date based on the calculation * APPEALS-45191. Lint fix --------- Co-authored-by: SHarshain * Chrisharsha/appeals 43962 (#21929) * Sharsha/appeals-44911_1 (#21784) * APPEALS-44911. Change the pure react components to functional components * APPEALS-44911. Redux implementation * APPEALS-44911. CSS changes for custom seed preview * APPEALS-44911. tweak css --------- Co-authored-by: SHarshain * Chrisbdetlef/appeals 44910 (#21838) * Initial * Add JSON parsing and multiple calls to rake tasks * Pre-caby tets * Add capybara tests and add IDs to buttons --------- Co-authored-by: Christopher Detlef <> --------- Co-authored-by: SHarshain Co-authored-by: cdetlefva <133903625+cdetlefva@users.noreply.github.com> * APPEALS-43962. Lint fixes (#21932) Co-authored-by: SHarshain * Ricky/APPEALS-47293 (#21925) * First pass implementation of fixing seeding rspecs * Second pass at fixing errors in rspecs * Revert updates to test if rspec passes * Fixed linting issues in test_docket_seeds_controller_spec --------- Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> * APPEALS-48292 updated the column to be a string (#21954) * APPEALS-48292 updated the column to be a string * APPEALS-48292 added comment to the control_group field in the migration * APPEALS-48292 added column comment to the schema, changed migration so that it can be rolled back * APPEALS-48598 fix logic when Start Distribution Prior to Docket Time Goal toggle is false (#21948) * APPEALS-48598 fix logic when Start Distribution Prior to Docket Time Goal toggle is false * APPEALS-49004 added spec to check when Start Distribution Prior to Docket Time Goal toggle is on * APPEALS-49004 fixed lint issues in docket.rb * APPEALS-48898. Created Distributable AMA Non-priority Appeals Query (#21949) * APPEALS-48898. Created Distributable AMA Non-priority Appeals Query * APPEALS-48898. Renamed the column and update the method --------- Co-authored-by: SHarshain * APPEALS-49100. getting value from the start_distribution_prior_to_goal (#21968) Co-authored-by: SHarshain * mbeard/APPEALS-46257 (#21976) * updates routes and frontend urls to namespace * removes superfluous tags * Ensure that legacy appeals are being created (#21981) * Ensure that legacy appeals are being created * Remove puts --------- Co-authored-by: Christopher Detlef <> * APPEALS-49403. Added buttons Docket Lever Seed (#21989) * APPEALS-49403. Added buttons Docket Lever Seed * sharsha/APPEALS-49403. Updated the endpoint URL path * APPEALS-49403. Lint fix --------- Co-authored-by: SHarshain * APPEALS-44000 added check to skip priority appeals in docket model (#21992) * Feature/appeals 36234 masterupgrade (#22003) * sbashamoni/APPEALS-43724 Node 16 version upgrade changes (#21966) (#21975) * Update node verstion to 16 in git workflow * Update node verstion to 16 in nvm and dockerfile for demo * Update node version in yarn.lock and package.json and .nvmrc file * Update node's version path to node16 in docker-bin/env.sh * Update and upgrade to node16 in client * More updates to yarn.lock and package.json * Fix tests by Adam Shaw * Upadate snapshot for ScheduleVeteran.test.js.snap * Doing some code clean up * Doiing some more clean up * Add and remove spaces to match master * One more space to take care of * One more space to take care of again * One more space to take care of again --------- Co-authored-by: ramon-chavez * init master merge branch --------- Co-authored-by: sbashamoni <138054633+sbashamoni@users.noreply.github.com> Co-authored-by: ramon-chavez * Remove AOD trait from non-priority legacy appeal creation (#22013) Co-authored-by: Christopher Detlef <> * Sharsha/appeals 49461 (#22018) * sharsha/APPEALS-49461. initial commit * sharsha/APPEALS-49461. fix --------- Co-authored-by: SHarshain * mbeard/APPEALS-49421 (#22014) * init commit fixes ama_np_ capybara test to expect user as admin, and first attempt test_docket_seeds test * removes previous chane for TASKS_LOADED * fixes capybara for test seeds controller button ids --------- Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> * APPEALS-49403. Updated the buttons label (#22025) Co-authored-by: SHarshain * mbeard/APPEALS-49585 (#22020) * init commit for non member view input * fixes css issue for docket-lever-right * Added a hyphen between value and unit for member only view * replaces hyphen with comma * Init commit replaces th with div for 508 compliance (#22036) * Chrisbdetlef/appeals 47008 1 (#22040) * Allow judges to see legacy cases and attorneys to be assigned cases * Remove testing function * Update spec to reflect new user count in seed file --------- Co-authored-by: Christopher Detlef <> * got rid of extraneous file * got rid of yarn lock orig * Include bandwidth as part of timeout error metric data (#21946) * Include bandwidth as part of timeout error metric data * add NetworkUtil.js file * fix code climate issues * fix linting issue * remove safari webdriver test * fix CI/CD issue with chrome_driver * add tests for NetworkUtil.js * move bandwidth to metric_attributes * requested changes* fix NetworkUtil-test --------- Co-authored-by: mikefinneran <110622959+mikefinneran@users.noreply.github.com> * APPEALS-50734. Remove Legacy appeals from the query (#22071) Co-authored-by: SHarshain * APPEALS-46087 fix css table width issues for case distribution lever history table (#22024) * Feature/appeals 36234.merge master.20240701 (#22075) * APPEALS-47277 remove Vegas office (#21876) * APPEALS-47277 remove Vagas office * Removed Texas ID from other files and updated tests * Snapshot update --------- Co-authored-by: Ron Wabukenda <130374706+ronwabVa@users.noreply.github.com> Co-authored-by: Raymond Hughes <131811099+raymond-hughes@users.noreply.github.com> * hotfix/APPEALS-22403 (#21942) * add identifier for filenumber or ssn in filenumber search * linting * codeclimate linting * update match call to return boolean --------- Co-authored-by: Ron Wabukenda <130374706+ronwabVa@users.noreply.github.com> Co-authored-by: Raymond Hughes <131811099+raymond-hughes@users.noreply.github.com> * APPEALS-46907: Update to Determination of Gen Pop Legacy Cases (#21986) * Isaiah/merge 46910 (#21983) * removed BFHINES checks and modified tests * removed lingering bfhines test * modified test * most recent updates on tests for passing status * removed refs to cavc updates * Skip flaky test ro_viewhearsched_spec --------- Co-authored-by: Isaiah Saucedo * APPEALS-44916: Case Distribution Affinity Calculations (#21899) * APPEALS-44956: Add AppealAffinity model and database table (#21526) * add migration for appeal_affinities * add AppealAffinity model and associations, update migration for new column * update index to be unique * add factory, add tests * add factory traits to appeal and case for appeal affinities * add combination trait to appeal factory * add appeal_affinity to skipped associations in ETL reporting * add a validation, test * Craig/appeals 44958 (#21564) * add new job, update affinity model validation and after save hook * add update from push job * fix job extending distribution scopes * add with appeal affinities to distribution scopes * typo * add error handling, add test file * add distributed case factory, refactor naming in job * fix factories, added tests * fix migration for null affinity start date column * fixes, added tests * more test updates * add return in job if no query results, tests for no query results * add test for after_save hook adding dist task instructions * set start dist job to queue affinity job after running * fix update job and start dist job spec * queue affinity update job from push job * code clarity * fix judge in seed file * remove comment, fix hearing factory, disable some seeds for testing * add more tests * test refactor * update appeals for dist query to add affinity start, add seed file, fix hearing factory, add stat to dist factory * disable new seed on reset * update seed file with vet names, add another seed category * fix distirbuted case factory? * actually fix GHA runs * lint, test fixes * change constants in new job * APPEALS-44959: Modify affinity date checks to use appeal_affinity (#21611) * swap distribution queries from distribution_task to appeal_affinities * update seed files to use appeal affinities instead of distribution task * clean up seed file method names * add missing Timecop.return in ama affinity case seed * fix name of a method in a seed file * remove references to distribution task in distribution scopes * fix push priority job tests * fix naming of args in one of the seed files * fix user seed, fix date format in distribution task instructions * fix tests for date format update * Calvin/APPEALS-44957-rake-affinity (#21577) * grabbed receipt dates from distributed cases * refactored for functionality + added method to grab appeals that match * using receipt date, get all related appeals * added update/creation plus cleaned prior imple. * gets most recent distributed case receipt_date * skips if receipt_date is nil for performance * if appeal affinity is nil, it will now be updated * created spec file * fixed non ready appeals * updated query to match new AC * removing comment * testing for each docket * updated spec file * added new tests to rspec * updated start date to receipt date instead of Time.now * fixed date/time rspec errors * added rails logger to know when rake task has finished * added tag for rails log * removed nonpriority dockets for direct_review and evidence_submission * fixed lint issue * fixed flaky spec test * limits distributed cases query to within the last week * APPEALS-46016: Add Affinity Start Date to the Explain Page (#21660) * add affinity start date to explain page * add feature test to verify dates display * update rake task and spec (#21731) * APPEALS-46325: Add Seeds for AOD Appeals and Update Dates to Match CAVC (#21730) * add aod hearing cases to ama affinity cases seed * fix lever spec * APPEALS-45148: Hook to clear saved affinity date (#21623) * initial imp. idea * AC1: check for affinity_start_date on assignment * AC2/3: update affinity start date w/ instr. * updates to naming, instructions, and hook logic * updates after review * rspec coverage and addtional condition * removed unused identifier * removed reduntant 'self's * added update on actual AA record * updated to save aa record and addtional rspec * added change to assignment on no record test * check for assignment * addd update to 'on_hold' status * public method to handle legacy affinity appeals * added .reload to :with_affinity_appeal * added .reload to :ready_for_distribution * updates to pass explain_spec * switched boolean values * typo * readujsted order on :create for affinity appeal * removed after(:create) * testing rspec by readding after :create * reloading in assertation * addressing lint errors * fix seeds/users_spec * add case dist lever to new tests (#21776) * remove unnecessarily included module from job (#21827) * APPEALS-47211: Improve Performance of Distribution Queries (#21840) * rework ready_for_distribution scope * fix non-hearing docket distribution bug * restart tests * added null checks for appeal affinity in distribution queries, update tests (#21893) * add check for appeal being active to distribution and associated slack message (#21902) * Update users_spec.rb --------- Co-authored-by: calvincostaBAH <108481161+calvincostaBAH@users.noreply.github.com> Co-authored-by: Isaiah Saucedo * hotfix/APPEALS-45177: TaskTable Default Sorting Fix (#21772) * Updated the TaskTable component to use the defaultSort property instead of the defaultSortIdx property for queue table since that property is not used anywhere. Added a default sorting hash to the UnassignedCasesPage component and now pass that down to TaskTable. Removed references to defaultSortIdx. * Added the type column default sort to the AssignedCasesPage widget as well. * Added a parenthesis for clarity around a boolean. Moved the defaultSortingHash out into a constants file. --------- Co-authored-by: Robert Travis Pierce * APPEALS-47106 Caseflow Swagger (#21993) * Add Rswag and convert existing API documentation (#21778) * add rswag * Update Gemfile.lock * Setup yaml UI * remove and reroute old swagger files * update format and servers values * Update route_docs_controller.rb * Update cmp_controller.rb * cmp endpoint yaml * cmp endpoint to return 501 * CMP endpoint swagger flies * update swagger files * adjust server order, add auth token * cmp parameter name change * add comments * Update users_controller.rb * unit tests and linting * lint fixes * Update swagger_helper.rb * APPEALS-48048 Swagger Updates (#21909) * update servers to not include a host * remove host for server * remove generated swaggers from definitions * remove internal API endpoints from having generated swagger * IDT servers fixes * disable CMP swagger in prod and prodtest * set authorization correctly * fix what is required for CMP upload * fix linting issues, update lint rake task to autocorrect for rubocop, add rubocop make command * Update decision_reviews.yaml * Update ama_issues.yaml * Update vacols_issues.yaml * Update swagger.yaml * fix check failures * Update docs_controller_spec.rb * fix unit tests * Update fetch_all_active_legacy_appeals_job_spec.rb * Update rswag_ui.rb * Update lint.rake * Update decision_reviews_spec.rb * Update fetch_all_active_legacy_appeals_job_spec.rb * Update veterans_controller_spec.rb * feature/APPEALS-43597 RC1.5.1 (#21996) * APPEALS-36759 Add sms_response_content and sms_response_time notifications table * APPEALS-37003 First pass at job refactor * APPEALS-37003 Add comments and update kwargs for va notify service * APPEALS-37003 Update spec files * APPEALS-37003 Update spec * APPEALS-37003 Ensure user in job and create email_enabled method * APPEALS-37003 Remove question mark * Limit max retry attempts to 5 * Add ? to boolen return methods * jcohen/APPEALS-43706 (#21444) * APPEALS-43706 macros added to each model file for the polymorphic relationship to be setup. * APPEALS-43706 migration made and yet to be run. * APPEALS-43706 migrations ran and expected columns and indexes are in table. * Fix some spec failures unrelated to this branch * Limit schema diff * Add a missing tab * Fix more unrelated failures. Also prevent ACD lever seeds from overwriting spec output * Fix last unrelated failure. * APPEALS-43706 linting issues in va_notify_service fixed. --------- Co-authored-by: Jonathan Cohen Co-authored-by: Matthew Thornton * [APPEALS-43598] Quarterly Notification Job refactoring (#21505) * Quarterly Notification Job refactoring * APPEALS-43598 Fix lint issues for QuarterlyNotificationsJob refactor * APPEALS-43598 Fix db schema.rb file * APPEALS-43598 Fix schema.rb file * APPEALS-43598 Refactoring QuarterlyNotificationsJob for readability * APPEALS-43598 Refactoring QuarterlyNotificationsJob and removing extra methods * [APPEALS-43598] Update method name --------- Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * APPEALS-44007: Eliminate Transmission of Notifications to Deceased Veterans (#21481) * APPEALS-44007: Writing tests to ensure adding the 'failure due to deceased' information is properly set and added to the db * updates to pr * pushing changes for tonight * updating spec file to handle enabling and disabling feature flags * Update format_message_status * Lint roll * fixing conflicts * Updates to send notification spec * Fix one of the legacy test cases * Remove accidental push * Fix remaining test --------- Co-authored-by: Noah Hansen Co-authored-by: Matthew Thornton Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * MattT/APPEALS-45235: Remove Temporary PDF Files From tmp Directory After All eFolder Upload Attempts (#21557) * Cleanup files after uploading to VBMS * Only delete file if it exists * Resolve linter issue * Update specs * Trigger CodeClimate --------- Co-authored-by: Matthew Thornton * Add appeal alias for notifiable * APPEALS-45346: Populate Polymorphic Association Columns When Creating New Notifications (#21575) * APPEALS-45346: Populate Polymorphic Association Columns When Creating New Notifications * fixing some errors * updating factory * updating tests * updating tests and factory * rubocop --------- Co-authored-by: Noah Hansen Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * APPEALS-43596 Adding JobMessageDeletionMiddleware to delete SQS messages for certain jobs * APPEALS-43596 Adding tests * APPEALS-43596 Fix codeclimate * APPEALS-43714: Refactor VANotify Modules to Not Rely on Class Variables (#21596) * APPEALS-43714: Refactor VANotify Modules to Not Rely on Class Variables * pushing changes * updating tests * rubocop * rubocop'n * deleting repeat constants * removing file in favor of EVENT_TYPE_FILTERS.json * removing instances of using VA_NOTIFY_TEMPLATE_NAMES and using EVENT_TYPE_FILTERS instead * replacing all instances of strings with constants * fixing bug * rubocop'n * rubocop'n * rubocop --------- Co-authored-by: Noah Hansen Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * Clean notification_events after notification report specs finish (#21662) Co-authored-by: Matthew Thornton * MattT/APPEALS-43725: Extract `notify_appellant` Call from `QuaterlyNotificationsJob` to Decrease Runtime (#21643) * Group notification types as scopes * Add new job * Fix typo * Add back batching * Batch send messages * Multithread job queueing * Reconfigure bulk enqueueing to utilize send_notifications.fifo queue * Update the comment on QuaterlyNotificationsJob#perform to adhere to the RDoc standard * Use constants for template name * Provide a more descriptive var name * Remove unused env var * Fix linting issues * Prevent error from being thrown early in init job * Add RDoc comments to appeal_state * Add rdoc comment to init job * Add another rdoc comment to the init job * Use a more specific error class whenever an appeal cannot be located within the init job * Add a more specific error to CaseflowJob#enqueue_batch_of_jobs * Add test for SendNotificationJob.queue_name_suffix * Update QuarterlyNotificationsJob tests * Update appeal_state_spec.rb to cover new scopes * Add spec file for NotificationInitializationJob * Add CaseflowJob specs * Add CaseflowJob specs * Address rubocop issue (by ignoring it) * Kicking off CodeClimate * Fix some lint issues * Freeze constant --------- Co-authored-by: Matthew Thornton * Move spec file to proper location * APPEALS-43599 (#21696) * APPEALS-43599 Refactoring SendNotificationJob * APPEALS-43599 Remove comments * APPEALS-43599 Suppress code smells from reek * APPEALS-43599 Suppress code smells from reek * jcohen/APPEALS-43727 (#21589) * APPEALS-43727 Branch created. Extracted all the 'when' conditions in the case statement within appellant_notification.rb update_appeal_state method. * APPEALS-43727 appellant_notification_service is created, logic from crowded method in appellant_notificaion.rb placed in newly created file, allowing redability. * APPEALS-43727 added logic to appeal_state.rb, appellant_notification.rb updated with less logic, readable code through well named methods. * APPEALS-43727 commit before merge from teammates work * APPEALS-43727 removed freeze method on default status hash in appeal_state.rb. removed some rubocop disabling in appellant_notificaion.rb * APPEALS-43727 extracted more logic from the appellant_notification module and placed it into the appeal_state class. Also got rid of rubocop declarations in app_notif and app_state as well. finally removed feature_toggle calls in appell_notif. * APPEALS-43727 tests passing, code works * APPEALS-43727 adding tests to appeal_state_spec to test functionality * APPEALS-43727 rspec tests in appeal_state. * APPEALS-43727 tests pass. * Fixing code climate duplicate code issue * fixing case statement * code climate things * rubocop * APPEALS-43727 work completed. * APPEALS-43727 PR comments applied. tests not in a working state. * APPEALS-43727 PR comments applied. appeal_state_spec in working state. * APPEALS-43727 PR comments applied. appellant_notification_spec.rb all green. * Adjust spacing of comments in appeal_state.rb * Utilize #external_id method over ternary * Swap or conditional for blank? * Fix another whitespace gap * APPEALS-43727 PR comments applied. again after reset. * APPEALS-43727 PR comments applied. flipped conditionals in appeal_state.rb * Update app/models/concerns/appeal_concern.rb * APPEALS-43727 code/test edits * APPEALS-43727 bulk_task_reasssignment_spec reverted to orginal state, with the exception of an expectation that was on line 98 * APPEALS-43727 lint fix --------- Co-authored-by: Jonathan Cohen Co-authored-by: Noah Hansen Co-authored-by: Matthew Thornton Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * APPEALS-46179 (#21712) * APPEALS-46179 Create JobExecutionTimes table * APPEALS-46179 Add comment * APPEALS-46179 Update schema * APPEALS-46193 (#21753) * APPEALS-46193 Add record to JobExecutionTime table when job is performed * APPEALS-46193 Updating JobExecutionTimes table with an upsert query * APPEALS-46193 Ignore JobExecutionTimes for certain jobs * APPEALS-46193 Update ignore_job_execution_time? method * APPEALS-46193 Adding tests * Fix lint issues * Update AWS dependencies * Rollback gem reduction due to UAT issue * Alter queue priority * Forward error in SendNotificationJob * Allow for notification audit records to remain in ProdTest * Fix spec * Fix typo in test fixture's name * Fix lint infraction related to re-raising exceptions * Address duplication CC error * Reenable-privacy-mail-notifications (#21859) * Add conditional for FOIA and Privacy Act mail task to receives 'Privacy Act Pending' notifications * Update spec * Adjust some specs * Add missing param --------- Co-authored-by: Matthew Thornton * Remove byebug from spec * Revert queue tweak * Remove duplicate method * APPEALS-47382: Refactor Job Behavior Filtering Boolean Methods (#21898) * initial commit * refactoring methods to have constants instead of methods * adding comments back in --------- Co-authored-by: Noah Hansen Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> Co-authored-by: nhansen3 * APPEALS-48342: Prevent Intentional Retries of SendNotificationJobs in ProdTest from Causing Duplicate Notification Table Entries (#21927) * initial commit * rubocop'n * rubcop'n * fixing tests --------- Co-authored-by: nhansen3 Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * Resolve missed conflict * MattT/APPEALS-48514 (#21959) * Prototype of privacy act fix * Leave privacy act states intact upon decision mailed * Remove unused param * Attempt updating specs to cover new behavior * Fix attr name typo * Add missing bang * Skip reek issue The issue has been deemed to be minor enough to not warrant having to reinvent everything for now. --------- Co-authored-by: Matthew Thornton * Fix quarterly specs by add in necessary hearings * Adjust spacing/ordering of gems (#21978) * MattT/APPEALS-49085 (#21960) * Filter out appeals whose hearings have been held from hearing_scheduled scope * Fix whitespace issues * Fix failing specs caused by an oversight on my part * Fix lint issue --------- Co-authored-by: Matthew Thornton * MattT/APPEALS-49212 (#21991) * Add module to set hearing_scheduled to false whenever hearings are marked as held * Add module to set hearing_scheduled to false whenever hearings are marked as held * Add step to NightlySyncsJob to sync hearing dispositions and appeal stateS * Add comment to new method * Use constant for disposition type * Fix typo in accessor * Add spec for new appeal state action * Create user in top scope * Expand nighlty syncs job to check all scheduled hearing disposition types. No show was left off as we don't have a requirement around it yet. * Add nightly sync job spec * Add disp task spec * Add specs targeting the hearings controller * Add sync script * Eager load constants * Add distinct * Remove appeal_docketed from being reset * Add script to adjust ama hearing statuses * Correct mistype * Add appeal_type clause * Fix specs * Lint fixes * Flip conditionals in specs * Fix var name * Fix var --------- Co-authored-by: Matthew Thornton * Backfill addition to script * Add AppealState record for newly docketed LegacyAppeals (#21999) * APPEALS-48966 Adding AppealState record for recently docketed appeals * APPEALS-48966 Refactor code and add comments * Delete extraneous files * Revert to using constants value --------- Co-authored-by: Matthew Thornton * Fix typo --------- Co-authored-by: Jeff Marks Co-authored-by: Matthew Thornton Co-authored-by: Jonathan Cohen <121630615+JCohDev@users.noreply.github.com> Co-authored-by: Jonathan Cohen Co-authored-by: prernadevbah <132498915+prernadevbah@users.noreply.github.com> Co-authored-by: noahhansen-gov <166541737+noahhansen-gov@users.noreply.github.com> Co-authored-by: Noah Hansen Co-authored-by: Prerna Devulapalli Co-authored-by: nhansen3 Co-authored-by: Marc Steele <71673522+msteele96@users.noreply.github.com> * Feature/appeals 43597 release candidate (#22004) * APPEALS-36759 Add sms_response_content and sms_response_time notifications table * APPEALS-37003 First pass at job refactor * APPEALS-37003 Add comments and update kwargs for va notify service * APPEALS-37003 Update spec files * APPEALS-37003 Update spec * APPEALS-37003 Ensure user in job and create email_enabled method * APPEALS-37003 Remove question mark * Limit max retry attempts to 5 * Add ? to boolen return methods * jcohen/APPEALS-43706 (#21444) * APPEALS-43706 macros added to each model file for the polymorphic relationship to be setup. * APPEALS-43706 migration made and yet to be run. * APPEALS-43706 migrations ran and expected columns and indexes are in table. * Fix some spec failures unrelated to this branch * Limit schema diff * Add a missing tab * Fix more unrelated failures. Also prevent ACD lever seeds from overwriting spec output * Fix last unrelated failure. * APPEALS-43706 linting issues in va_notify_service fixed. --------- Co-authored-by: Jonathan Cohen Co-authored-by: Matthew Thornton * [APPEALS-43598] Quarterly Notification Job refactoring (#21505) * Quarterly Notification Job refactoring * APPEALS-43598 Fix lint issues for QuarterlyNotificationsJob refactor * APPEALS-43598 Fix db schema.rb file * APPEALS-43598 Fix schema.rb file * APPEALS-43598 Refactoring QuarterlyNotificationsJob for readability * APPEALS-43598 Refactoring QuarterlyNotificationsJob and removing extra methods * [APPEALS-43598] Update method name --------- Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * APPEALS-44007: Eliminate Transmission of Notifications to Deceased Veterans (#21481) * APPEALS-44007: Writing tests to ensure adding the 'failure due to deceased' information is properly set and added to the db * updates to pr * pushing changes for tonight * updating spec file to handle enabling and disabling feature flags * Update format_message_status * Lint roll * fixing conflicts * Updates to send notification spec * Fix one of the legacy test cases * Remove accidental push * Fix remaining test --------- Co-authored-by: Noah Hansen Co-authored-by: Matthew Thornton Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * MattT/APPEALS-45235: Remove Temporary PDF Files From tmp Directory After All eFolder Upload Attempts (#21557) * Cleanup files after uploading to VBMS * Only delete file if it exists * Resolve linter issue * Update specs * Trigger CodeClimate --------- Co-authored-by: Matthew Thornton * Add appeal alias for notifiable * APPEALS-45346: Populate Polymorphic Association Columns When Creating New Notifications (#21575) * APPEALS-45346: Populate Polymorphic Association Columns When Creating New Notifications * fixing some errors * updating factory * updating tests * updating tests and factory * rubocop --------- Co-authored-by: Noah Hansen Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * APPEALS-43596 Adding JobMessageDeletionMiddleware to delete SQS messages for certain jobs * APPEALS-43596 Adding tests * APPEALS-43596 Fix codeclimate * APPEALS-43714: Refactor VANotify Modules to Not Rely on Class Variables (#21596) * APPEALS-43714: Refactor VANotify Modules to Not Rely on Class Variables * pushing changes * updating tests * rubocop * rubocop'n * deleting repeat constants * removing file in favor of EVENT_TYPE_FILTERS.json * removing instances of using VA_NOTIFY_TEMPLATE_NAMES and using EVENT_TYPE_FILTERS instead * replacing all instances of strings with constants * fixing bug * rubocop'n * rubocop'n * rubocop --------- Co-authored-by: Noah Hansen Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * Clean notification_events after notification report specs finish (#21662) Co-authored-by: Matthew Thornton * MattT/APPEALS-43725: Extract `notify_appellant` Call from `QuaterlyNotificationsJob` to Decrease Runtime (#21643) * Group notification types as scopes * Add new job * Fix typo * Add back batching * Batch send messages * Multithread job queueing * Reconfigure bulk enqueueing to utilize send_notifications.fifo queue * Update the comment on QuaterlyNotificationsJob#perform to adhere to the RDoc standard * Use constants for template name * Provide a more descriptive var name * Remove unused env var * Fix linting issues * Prevent error from being thrown early in init job * Add RDoc comments to appeal_state * Add rdoc comment to init job * Add another rdoc comment to the init job * Use a more specific error class whenever an appeal cannot be located within the init job * Add a more specific error to CaseflowJob#enqueue_batch_of_jobs * Add test for SendNotificationJob.queue_name_suffix * Update QuarterlyNotificationsJob tests * Update appeal_state_spec.rb to cover new scopes * Add spec file for NotificationInitializationJob * Add CaseflowJob specs * Add CaseflowJob specs * Address rubocop issue (by ignoring it) * Kicking off CodeClimate * Fix some lint issues * Freeze constant --------- Co-authored-by: Matthew Thornton * Move spec file to proper location * APPEALS-43599 (#21696) * APPEALS-43599 Refactoring SendNotificationJob * APPEALS-43599 Remove comments * APPEALS-43599 Suppress code smells from reek * APPEALS-43599 Suppress code smells from reek * jcohen/APPEALS-43727 (#21589) * APPEALS-43727 Branch created. Extracted all the 'when' conditions in the case statement within appellant_notification.rb update_appeal_state method. * APPEALS-43727 appellant_notification_service is created, logic from crowded method in appellant_notificaion.rb placed in newly created file, allowing redability. * APPEALS-43727 added logic to appeal_state.rb, appellant_notification.rb updated with less logic, readable code through well named methods. * APPEALS-43727 commit before merge from teammates work * APPEALS-43727 removed freeze method on default status hash in appeal_state.rb. removed some rubocop disabling in appellant_notificaion.rb * APPEALS-43727 extracted more logic from the appellant_notification module and placed it into the appeal_state class. Also got rid of rubocop declarations in app_notif and app_state as well. finally removed feature_toggle calls in appell_notif. * APPEALS-43727 tests passing, code works * APPEALS-43727 adding tests to appeal_state_spec to test functionality * APPEALS-43727 rspec tests in appeal_state. * APPEALS-43727 tests pass. * Fixing code climate duplicate code issue * fixing case statement * code climate things * rubocop * APPEALS-43727 work completed. * APPEALS-43727 PR comments applied. tests not in a working state. * APPEALS-43727 PR comments applied. appeal_state_spec in working state. * APPEALS-43727 PR comments applied. appellant_notification_spec.rb all green. * Adjust spacing of comments in appeal_state.rb * Utilize #external_id method over ternary * Swap or conditional for blank? * Fix another whitespace gap * APPEALS-43727 PR comments applied. again after reset. * APPEALS-43727 PR comments applied. flipped conditionals in appeal_state.rb * Update app/models/concerns/appeal_concern.rb * APPEALS-43727 code/test edits * APPEALS-43727 bulk_task_reasssignment_spec reverted to orginal state, with the exception of an expectation that was on line 98 * APPEALS-43727 lint fix --------- Co-authored-by: Jonathan Cohen Co-authored-by: Noah Hansen Co-authored-by: Matthew Thornton Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * APPEALS-46179 (#21712) * APPEALS-46179 Create JobExecutionTimes table * APPEALS-46179 Add comment * APPEALS-46179 Update schema * APPEALS-46193 (#21753) * APPEALS-46193 Add record to JobExecutionTime table when job is performed * APPEALS-46193 Updating JobExecutionTimes table with an upsert query * APPEALS-46193 Ignore JobExecutionTimes for certain jobs * APPEALS-46193 Update ignore_job_execution_time? method * APPEALS-46193 Adding tests * Fix lint issues * Update AWS dependencies * Rollback gem reduction due to UAT issue * Alter queue priority * Forward error in SendNotificationJob * Allow for notification audit records to remain in ProdTest * Fix spec * Fix typo in test fixture's name * Fix lint infraction related to re-raising exceptions * Address duplication CC error * Reenable-privacy-mail-notifications (#21859) * Add conditional for FOIA and Privacy Act mail task to receives 'Privacy Act Pending' notifications * Update spec * Adjust some specs * Add missing param --------- Co-authored-by: Matthew Thornton * Remove byebug from spec * Revert queue tweak * Remove duplicate method * APPEALS-47382: Refactor Job Behavior Filtering Boolean Methods (#21898) * initial commit * refactoring methods to have constants instead of methods * adding comments back in --------- Co-authored-by: Noah Hansen Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> Co-authored-by: nhansen3 * APPEALS-48342: Prevent Intentional Retries of SendNotificationJobs in ProdTest from Causing Duplicate Notification Table Entries (#21927) * initial commit * rubocop'n * rubcop'n * fixing tests --------- Co-authored-by: nhansen3 Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> * Resolve missed conflict * MattT/APPEALS-48514 (#21959) * Prototype of privacy act fix * Leave privacy act states intact upon decision mailed * Remove unused param * Attempt updating specs to cover new behavior * Fix attr name typo * Add missing bang * Skip reek issue The issue has been deemed to be minor enough to not warrant having to reinvent everything for now. --------- Co-authored-by: Matthew Thornton * Fix quarterly specs by add in necessary hearings * Adjust spacing/ordering of gems (#21978) * MattT/APPEALS-49085 (#21960) * Filter out appeals whose hearings have been held from hearing_scheduled scope * Fix whitespace issues * Fix failing specs caused by an oversight on my part * Fix lint issue --------- Co-authored-by: Matthew Thornton * MattT/APPEALS-49212 (#21991) * Add module to set hearing_scheduled to false whenever hearings are marked as held * Add module to set hearing_scheduled to false whenever hearings are marked as held * Add step to NightlySyncsJob to sync hearing dispositions and appeal stateS * Add comment to new method * Use constant for disposition type * Fix typo in accessor * Add spec for new appeal state action * Create user in top scope * Expand nighlty syncs job to check all scheduled hearing disposition types. No show was left off as we don't have a requirement around it yet. * Add nightly sync job spec * Add disp task spec * Add specs targeting the hearings controller * Add sync script * Eager load constants * Add distinct * Remove appeal_docketed from being reset * Add script to adjust ama hearing statuses * Correct mistype * Add appeal_type clause * Fix specs * Lint fixes * Flip conditionals in specs * Fix var name * Fix var --------- Co-authored-by: Matthew Thornton * Backfill addition to script * Add AppealState record for newly docketed LegacyAppeals (#21999) * APPEALS-48966 Adding AppealState record for recently docketed appeals * APPEALS-48966 Refactor code and add comments * Delete extraneous files * Revert to using constants value --------- Co-authored-by: Matthew Thornton * Fix typo * Fix typo * Fix seed script * Fix seed script * Ensure cleanup * Change copy for Appeal Docketed status (#22006) * Change copy for Appeal Docketed status * Change case --------- Co-authored-by: Matthew Thornton * Use status text value instead of key --------- Co-authored-by: Jeff Marks Co-authored-by: Matthew Thornton Co-authored-by: Jonathan Cohen <121630615+JCohDev@users.noreply.github.com> Co-authored-by: Jonathan Cohen Co-authored-by: prernadevbah <132498915+prernadevbah@users.noreply.github.com> Co-authored-by: noahhansen-gov <166541737+noahhansen-gov@users.noreply.github.com> Co-authored-by: Noah Hansen Co-authored-by: Prerna Devulapalli Co-authored-by: nhansen3 Co-authored-by: Marc Steele <71673522+msteele96@users.noreply.github.com> * APPEALS-44916 seed data update (#22008) * APPEALS-44956: Add AppealAffinity model and database table (#21526) * add migration for appeal_affinities * add AppealAffinity model and associations, update migration for new column * update index to be unique * add factory, add tests * add factory traits to appeal and case for appeal affinities * add combination trait to appeal factory * add appeal_affinity to skipped associations in ETL reporting * add a validation, test * Craig/appeals 44958 (#21564) * add new job, update affinity model validation and after save hook * add update from push job * fix job extending distribution scopes * add with appeal affinities to distribution scopes * typo * add error handling, add test file * add distributed case factory, refactor naming in job * fix factories, added tests * fix migration for null affinity start date column * fixes, added tests * more test updates * add return in job if no query results, tests for no query results * add test for after_save hook adding dist task instructions * set start dist job to queue affinity job after running * fix update job and start dist job spec * queue affinity update job from push job * code clarity * fix judge in seed file * remove comment, fix hearing factory, disable some seeds for testing * add more tests * test refactor * update appeals for dist query to add affinity start, add seed file, fix hearing factory, add stat to dist factory * disable new seed on reset * update seed file with vet names, add another seed category * fix distirbuted case factory? * actually fix GHA runs * lint, test fixes * change constants in new job * APPEALS-44959: Modify affinity date checks to use appeal_affinity (#21611) * swap distribution queries from distribution_task to appeal_affinities * update seed files to use appeal affinities instead of distribution task * clean up seed file method names * add missing Timecop.return in ama affinity case seed * fix name of a method in a seed file * remove references to distribution task in distribution scopes * fix push priority job tests * fix naming of args in one of the seed files * fix user seed, fix date format in distribution task instructions * fix tests for date format update * Calvin/APPEALS-44957-rake-affinity (#21577) * grabbed receipt dates from distributed cases * refactored for functionality + added method to grab appeals that match * using receipt date, get all related appeals * added update/creation plus cleaned prior imple. * gets most recent distributed case receipt_date * skips if receipt_date is nil for performance * if appeal affinity is nil, it will now be updated * created spec file * fixed non ready appeals * updated query to match new AC * removing comment * testing for each docket * updated spec file * added new tests to rspec * updated start date to receipt date instead of Time.now * fixed date/time rspec errors * added rails logger to know when rake task has finished * added tag for rails log * removed nonpriority dockets for direct_review and evidence_submission * fixed lint issue * fixed flaky spec test * limits distributed cases query to within the last week * APPEALS-46016: Add Affinity Start Date to the Explain Page (#21660) * add affinity start date to explain page * add feature test to verify dates display * update rake task and spec (#21731) * APPEALS-46325: Add Seeds for AOD Appeals and Update Dates to Match CAVC (#21730) * add aod hearing cases to ama affinity cases seed * fix lever spec * APPEALS-45148: Hook to clear saved affinity date (#21623) * initial imp. idea * AC1: check for affinity_start_date on assignment * AC2/3: update affinity start date w/ instr. * updates to naming, instructions, and hook logic * updates after review * rspec coverage and addtional condition * removed unused identifier * removed reduntant 'self's * added update on actual AA record * updated to save aa record and addtional rspec * added change to assignment on no record test * check for assignment * addd update to 'on_hold' status * public method to handle legacy affinity appeals * added .reload to :with_affinity_appeal * added .reload to :ready_for_distribution * updates to pass explain_spec * switched boolean values * typo * readujsted order on :create for affinity appeal * removed after(:create) * testing rspec by readding after :create * reloading in assertation * addressing lint errors * fix seeds/users_spec * add case dist lever to new tests (#21776) * remove unnecessarily included module from job (#21827) * APPEALS-47211: Improve Performance of Distribution Queries (#21840) * rework ready_for_distribution scope * fix non-hearing docket distribution bug * restart tests * added null checks for appeal affinity in distribution queries, update tests (#21893) * add check for appeal being active to distribution and associated slack message (#21902) * prelim work on 48033 * refactored code a bit, working on data creation now * created ama_affinity data * fixing mispelt variable * add back line that was removed * updated users_spec to now pass --------- Co-authored-by: calvincostaBAH <108481161+calvincostaBAH@users.noreply.github.com> Co-authored-by: Isaiah Saucedo Co-authored-by: Sean Parker Co-authored-by: Calvin * fixed merge conflict --------- Co-authored-by: alex-guanipatin <143651918+alex-guanipatin@users.noreply.github.com> Co-authored-by: Ron Wabukenda <130374706+ronwabVa@users.noreply.github.com> Co-authored-by: Raymond Hughes <131811099+raymond-hughes@users.noreply.github.com> Co-authored-by: slwallerBAH <161883271+slwallerBAH@users.noreply.github.com> Co-authored-by: Craig Reese <109101548+craigrva@users.noreply.github.com> Co-authored-by: Isaiah Saucedo Co-authored-by: calvincostaBAH <108481161+calvincostaBAH@users.noreply.github.com> Co-authored-by: Tyler Broyles <109369527+TylerBroyles@users.noreply.github.com> Co-authored-by: Robert Travis Pierce Co-authored-by: Matt Roth Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> Co-authored-by: Jeff Marks Co-authored-by: Matthew Thornton Co-authored-by: Jonathan Cohen <121630615+JCohDev@users.noreply.github.com> Co-authored-by: Jonathan Cohen Co-authored-by: prernadevbah <132498915+prernadevbah@users.noreply.github.com> Co-authored-by: noahhansen-gov <166541737+noahhansen-gov@users.noreply.github.com> Co-authored-by: Noah Hansen Co-authored-by: Prerna Devulapalli Co-authored-by: nhansen3 Co-authored-by: Marc Steele <71673522+msteele96@users.noreply.github.com> Co-authored-by: Sean Parker Co-authored-by: Calvin * Revert "APPEALS-46087 fix css table width issues for case distribution lever history table (#22024)" This reverts commit 05896d32fa0510bf76101dff689ad05187dc7ccf. * Removed Test Seeds link from dropdown menu (#22089) * Resolve merge issues (#22103) * resolve issues * fix controller spec * Include bandwidth as part of timeout error metric data (#21946) (#22105) Co-authored-by: Daniel Mage * fix hearing_request_docket_spec merge issue * Hotfix/appeals 44031 (#22104) (#22111) * Hotfix/appeals 44031 (#22104) * Hotfix/appeals 44031 b (#22110) --------- Co-authored-by: Daniel Mage --------- Co-authored-by: Blake Manus <33578594+Blake-Manus@users.noreply.github.com> Co-authored-by: 631966 Co-authored-by: sbashamoni Co-authored-by: sbashamoni <138054633+sbashamoni@users.noreply.github.com> Co-authored-by: Michael Beard <131783726+mbeardy@users.noreply.github.com> Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> Co-authored-by: cdetlefva <133903625+cdetlefva@users.noreply.github.com> Co-authored-by: SHarshain Co-authored-by: Michael Beard Co-authored-by: SHarshain <133917878+SHarshain@users.noreply.github.com> Co-authored-by: 631068 Co-authored-by: Isaiah Saucedo Co-authored-by: Calvin Co-authored-by: youfoundmanesh Co-authored-by: Craig Reese <109101548+craigrva@users.noreply.github.com> Co-authored-by: Robert Travis Pierce Co-authored-by: Jeremy Croteau Co-authored-by: davis-dwayne <47563178+davis-dwayne@users.noreply.github.com> Co-authored-by: kristeja <112115264+kristeja@users.noreply.github.com> Co-authored-by: Craig Reese Co-authored-by: ramon-chavez Co-authored-by: Matt Roth Co-authored-by: Daniel Mage Co-authored-by: alex-guanipatin <143651918+alex-guanipatin@users.noreply.github.com> Co-authored-by: Ron Wabukenda <130374706+ronwabVa@users.noreply.github.com> Co-authored-by: Raymond Hughes <131811099+raymond-hughes@users.noreply.github.com> Co-authored-by: slwallerBAH <161883271+slwallerBAH@users.noreply.github.com> Co-authored-by: calvincostaBAH <108481161+calvincostaBAH@users.noreply.github.com> Co-authored-by: Tyler Broyles <109369527+TylerBroyles@users.noreply.github.com> Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> Co-authored-by: Jeff Marks Co-authored-by: Matthew Thornton Co-authored-by: Jonathan Cohen <121630615+JCohDev@users.noreply.github.com> Co-authored-by: Jonathan Cohen Co-authored-by: prernadevbah <132498915+prernadevbah@users.noreply.github.com> Co-authored-by: noah… --------- Co-authored-by: youfoundmanesh <129548081+youfoundmanesh@users.noreply.github.com> Co-authored-by: samasudhirreddy <108430298+samasudhirreddy@users.noreply.github.com> Co-authored-by: Robert Travis Pierce Co-authored-by: Clay Sheppard Co-authored-by: Brandon Lee Dorner Co-authored-by: jonathanh-va <111081469+jonathanh-va@users.noreply.github.com> Co-authored-by: Jonathan Hoang Co-authored-by: Prajwal Amatya <122557351+pamatyatake2@users.noreply.github.com> Co-authored-by: almorbah Co-authored-by: Tyler Broyles <109369527+TylerBroyles@users.noreply.github.com> Co-authored-by: Brandon Dorner Co-authored-by: Sean Craig <110493538+seancva@users.noreply.github.com> Co-authored-by: = Co-authored-by: almorbah <149511814+almorbah@users.noreply.github.com> Co-authored-by: Robert Travis Pierce Co-authored-by: Prajwal Amatya Co-authored-by: alex-guanipatin <143651918+alex-guanipatin@users.noreply.github.com> Co-authored-by: Ron Wabukenda <130374706+ronwabVa@users.noreply.github.com> Co-authored-by: mikefinneran <110622959+mikefinneran@users.noreply.github.com> Co-authored-by: Blake Manus <33578594+Blake-Manus@users.noreply.github.com> Co-authored-by: 631966 Co-authored-by: sbashamoni Co-authored-by: sbashamoni <138054633+sbashamoni@users.noreply.github.com> Co-authored-by: Michael Beard <131783726+mbeardy@users.noreply.github.com> Co-authored-by: Amy Detwiler <133032208+amybids@users.noreply.github.com> Co-authored-by: cdetlefva <133903625+cdetlefva@users.noreply.github.com> Co-authored-by: SHarshain Co-authored-by: Michael Beard Co-authored-by: SHarshain <133917878+SHarshain@users.noreply.github.com> Co-authored-by: 631068 Co-authored-by: Isaiah Saucedo Co-authored-by: Calvin Co-authored-by: youfoundmanesh Co-authored-by: Jeremy Croteau Co-authored-by: davis-dwayne <47563178+davis-dwayne@users.noreply.github.com> Co-authored-by: kristeja <112115264+kristeja@users.noreply.github.com> Co-authored-by: ramon-chavez Co-authored-by: Matt Roth Co-authored-by: Daniel Mage Co-authored-by: Raymond Hughes <131811099+raymond-hughes@users.noreply.github.com> Co-authored-by: slwallerBAH <161883271+slwallerBAH@users.noreply.github.com> Co-authored-by: calvincostaBAH <108481161+calvincostaBAH@users.noreply.github.com> Co-authored-by: Matthew Thornton <99351305+ThorntonMatthew@users.noreply.github.com> Co-authored-by: Jeff Marks Co-authored-by: Matthew Thornton Co-authored-by: Jonathan Cohen <121630615+JCohDev@users.noreply.github.com> Co-authored-by: Jonathan Cohen Co-authored-by: prernadevbah <132498915+prernadevbah@users.noreply.github.com> Co-authored-by: noahhansen-gov <166541737+noahhansen-gov@users.noreply.github.com> Co-authored-by: Noah Hansen Co-authored-by: Prerna Devulapalli Co-authored-by: nhansen3 Co-authored-by: Marc Steele <71673522+msteele96@users.noreply.github.com> Co-authored-by: Sean Parker --- Gemfile | 1 + Gemfile.lock | 20 +- app/controllers/application_controller.rb | 32 +- ...se_distribution_levers_tests_controller.rb | 27 + app/controllers/claim_review_controller.rb | 100 +- .../decision_reviews_controller.rb | 14 +- app/controllers/intakes_controller.rb | 1 + .../test_docket_seeds_controller.rb | 47 + app/controllers/test_seeds_controller.rb | 41 + .../push_priority_appeals_to_judges_job.rb | 8 +- app/mailers/dispatch_mailer.rb | 2 +- app/models/appeal.rb | 4 + app/models/case_distribution_lever.rb | 11 +- app/models/claim_review.rb | 12 +- .../concerns/by_docket_date_distribution.rb | 22 +- app/models/concerns/distribution_concern.rb | 2 +- app/models/concerns/distribution_scopes.rb | 9 +- app/models/decision_review.rb | 5 + app/models/distribution.rb | 2 - app/models/docket.rb | 59 +- app/models/docket_coordinator.rb | 4 - app/models/dockets/hearing_request_docket.rb | 31 +- app/models/dockets/legacy_docket.rb | 18 +- app/models/issue_modification_request.rb | 162 ++ app/models/organizations/business_line.rb | 63 +- app/models/organizations/vha_business_line.rb | 5 +- app/models/request_issue.rb | 1 + app/models/request_issues_update.rb | 15 +- .../decision_review_task_serializer.rb | 11 +- app/models/user.rb | 8 + ...als_non_priority_ready_for_distribution.rb | 97 + app/queries/appeals_ready_for_distribution.rb | 58 +- app/queries/appeals_updated_since_query.rb | 1 + .../intake/decision_review_serializer.rb | 5 + .../issue_modification_request_serializer.rb | 22 + .../issue_modification_requests/updater.rb | 93 + app/views/appeals/edit.html.erb | 4 + app/views/higher_level_reviews/edit.html.erb | 4 + app/views/supplemental_claims/edit.html.erb | 4 + app/views/test/seeds.html.erb | 8 + client/COPY.json | 65 +- .../components/DocketTimeGoals.jsx | 6 +- .../components/ExcludeDocketLever.jsx | 27 + .../components/ExclusionTable.jsx | 313 ++- .../components/LeverHistory.jsx | 2 +- client/app/caseDistribution/constants.js | 6 +- .../pages/CaseDistributionApp.jsx | 2 +- client/app/caseDistribution/test.jsx | 69 +- client/app/components/Modal.jsx | 16 +- client/app/components/Modal.stories.js | 4 + client/app/components/NumberField.jsx | 2 + client/app/components/SearchableDropdown.jsx | 21 +- .../components/ToggleSwitch/ToggleSwitch.jsx | 7 +- client/app/index.js | 7 +- client/app/intake/IntakeFrame.jsx | 1 + .../actions/issueModificationRequest.js | 91 + .../AddDecisionDateModal.test.js.snap | 210 +- .../app/intake/components/AddIssueManager.jsx | 7 +- .../app/intake/components/AddIssuesModal.jsx | 2 + .../components/AddIssuesModal.stories.js | 3 +- .../CancelPendingRequestIssueModal.jsx | 113 + .../ConfirmPendingRequestIssueModal.jsx | 90 + client/app/intake/components/IssueList.jsx | 66 +- .../app/intake/components/IssueList.test.js | 38 +- .../components/IssueModificationList.jsx | 51 + .../components/IssueModificationRequest.jsx | 155 ++ .../components/IssueModificationRow.jsx | 59 + .../IssueModificationRow.stories.js | 116 + .../components/NonratingRequestIssueModal.jsx | 34 +- .../NonratingRequestIssueModal.stories.js | 12 + .../RemoveIssueModal/RemoveIssueModal.jsx | 34 +- .../components/UnidentifiedIssuesModal.jsx | 52 +- client/app/intake/constants.js | 17 +- .../app/intake/pages/addIssues/addIssues.jsx | 305 ++- .../IssueSectionRow.stories.js | 22 +- .../issueSectionRow/issueSectionRow.jsx | 11 +- .../addIssues/issueSectionRow/mockData.js | 58 +- client/app/intake/reducers/common.js | 179 ++ client/app/intake/selectors.js | 11 + .../intake/util/issueModificationRequests.js | 120 + client/app/intake/util/issues.js | 11 +- client/app/intakeEdit/IntakeEditFrame.jsx | 7 + client/app/intakeEdit/actions/edit.js | 30 +- .../app/intakeEdit/components/EditButtons.jsx | 37 +- .../PendingIssueModificationRequestBanner.jsx | 21 + .../RequestCommonComponents/CurrentIssue.jsx | 23 + .../IssueDescription.jsx | 15 + .../IssueTypeSelector.jsx | 35 + .../PriorDecisionDateAlert.jsx | 19 + .../PriorDecisionDateSelector.jsx | 16 + .../RequestIssueFormWrapper.jsx | 194 ++ .../RequestIssueStatus.jsx | 116 + .../RequestCommonComponents/RequestReason.jsx | 27 + .../components/RequestIssueAdditionModal.jsx | 60 + .../components/RequestIssueModals.stories.js | 104 + .../RequestIssueModificationModal.jsx | 67 + .../components/RequestIssueRemovalModal.jsx | 65 + .../RequestIssueWithdrawalModal.jsx | 76 + .../components/SaveAlertConfirmModal.jsx | 5 +- client/app/intakeEdit/reducers/index.js | 12 + client/app/nonComp/components/Alerts.jsx | 5 + client/app/nonComp/components/Disposition.jsx | 51 +- client/app/nonComp/components/NonCompTabs.jsx | 35 +- .../nonComp/components/TaskTableColumns.jsx | 10 + .../app/nonComp/components/TaskTableTab.jsx | 15 +- client/app/nonComp/pages/TaskPage.jsx | 4 +- client/app/queue/utils.js | 5 +- client/app/reader/PdfFile.jsx | 36 +- client/app/styles/_intake.scss | 45 +- client/app/styles/_noncomp.scss | 17 +- .../caseDistribution/_case_distribution.scss | 1 + .../caseDistribution/_exclusion_table.scss | 2 +- .../_interactable_levers.scss | 1 + .../caseDistribution/_lever_history.scss | 18 +- .../styles/caseDistribution/_test_seeds.scss | 124 + client/app/styles/react/_toggle_switch.scss | 8 + .../app/testSeeds/components/CustomSeeds.jsx | 254 ++ .../components/SeedsBannerDisplay.jsx | 24 + .../testSeeds/components/TestSeedsWrapper.jsx | 12 + client/app/testSeeds/index.jsx | 77 + client/app/testSeeds/pages/TestSeedsApp.jsx | 14 + client/app/testSeeds/reducers/root.js | 12 + .../reducers/seeds/seedsActionTypes.js | 6 + .../testSeeds/reducers/seeds/seedsActions.js | 41 + .../testSeeds/reducers/seeds/seedsReducer.js | 38 + client/app/util/NetworkUtil.js | 39 + client/constants/ACD_LEVERS.json | 2 + client/constants/CUSTOM_SEEDS.json | 6 + client/constants/DISTRIBUTION.json | 24 +- client/constants/QUEUE_CONFIG.json | 74 +- .../REGIONAL_OFFICE_FACILITY_ADDRESS.json | 22 +- .../REGIONAL_OFFICE_INFORMATION.json | 4 +- client/constants/TEST_SEEDS.json | 10 + .../components/DocketTimeGoals.test.js | 4 +- .../components/ExcludeDocketLever.test.js | 73 + .../components/ExclusionTable.test.js | 53 + .../reducers/levers/LeversReducer.test.js | 4 +- .../__snapshots__/Modal.test.js.snap | 25 +- .../components/ScheduleVeteranForm.test.js | 3 +- .../EditUnscheduledNotesModal.test.js.snap | 59 +- .../EmailConfirmationModal.test.js.snap | 2288 +++++++++-------- .../HearingTypeConversionModal.test.js.snap | 68 +- .../ScheduleVeteran.test.js.snap | 480 ++++ .../ScheduleVeteranForm.test.js.snap | 320 +++ .../__snapshots__/TimeModal.test.js.snap | 149 +- .../intake/NonratingRequestIssueModal-test.js | 53 + .../CancelPendingRequestIssueModal.test.js | 100 + .../ConfirmPendingRequestIssueModal.test.js | 51 + .../components/IssueModificationList.test.js | 151 ++ .../RemoveIssueModal.test.jsx | 2 +- .../CancelIntakeModal.test.js.snap | 386 ++- .../ConfirmClaimLabelModal.test.js.snap | 41 +- .../EditClaimLabelModal.test.js.snap | 171 +- .../AddClaimantConfirmationModal.test.js.snap | 560 ++-- client/test/app/intake/testData.js | 1 + .../util/__snapshots__/issues.test.js.snap | 4 + client/test/app/nonComp/NonCompTabs.test.js | 54 +- .../__snapshots__/ReviewPage.test.js.snap | 34 +- .../AddCavcDatesModal.test.js.snap | 586 +++-- ...vcReviewExtensionRequestModal.test.js.snap | 272 +- .../EditNodDateModal.test.js.snap | 211 +- client/test/app/reader/PdfFile-test.js | 193 +- .../testSeeds/components/CustomSeeds.test.js | 164 ++ .../app/testSeeds/pages/TestSeedsApp.test.js | 33 + .../test/app/testSeeds/reducers/root.test.js | 29 + .../reducers/seeds/seedsActions.test.js | 67 + .../reducers/seeds/seedsReducer.test.js | 72 + client/test/app/util/NetworkUtil-test.js | 42 + .../test/data/adminCaseDistributionLevers.js | 227 +- .../data/formattedCaseDistributionData.js | 4 +- client/test/data/intakeEdit/store.js | 200 ++ .../test/data/issueModificationListProps.js | 111 + .../data/regionalOfficesJsonResponse.json | 4 +- client/test/data/taskFilterDetails.js | 2 + config/routes.rb | 22 +- ...15736_create_issue_modification_request.rb | 23 + ...up_data_type_in_case_distribution_lever.rb | 6 + db/schema.rb | 33 +- db/seeds.rb | 1 + db/seeds/ama_affinity_cases.rb | 71 +- db/seeds/case_distribution_levers.rb | 179 +- db/seeds/demo_ama_aod_hearing_data.rb | 83 + .../demo_ama_docket_goals_lever_test_data.rb | 332 +++ db/seeds/demo_ama_non_aod_hearing_data.rb | 82 + db/seeds/demo_direct_reviews_data.rb | 79 + .../demo_docket_priority_lever_test_data.rb | 690 +++++ db/seeds/demo_legacy_cases_data.rb | 106 + db/seeds/issue_modification_request.rb | 75 + db/seeds/users.rb | 11 +- lib/caseflow/error.rb | 5 + public/sample_custom_seeds.csv | 1 + scripts/enable_features_dev.rb | 2 - ...ase_distribution_levers_controller_spec.rb | 27 +- .../decision_reviews_controller_spec.rb | 108 + .../higher_level_reviews_controller_spec.rb | 58 + .../supplemental_claims_controller_spec.rb | 58 + .../test_docket_seeds_controller_spec.rb | 600 +++++ spec/factories/case_distribution_lever.rb | 192 ++ spec/factories/hearing.rb | 5 +- spec/factories/issue_modification_request.rb | 67 + spec/factories/task.rb | 40 + spec/factories/user.rb | 19 + spec/factories/vacols/staff.rb | 5 + .../ama_np_dist_goals_by_docket_lever_spec.rb | 25 +- spec/feature/intake/appeal/edit_spec.rb | 20 +- .../intake/edit_ep_claim_labels_spec.rb | 5 +- .../intake/higher_level_review/edit_spec.rb | 67 +- .../intake/issue_modification_request_spec.rb | 558 ++++ .../intake/reassign_cases_to_camo_spec.rb | 404 +++ .../intake/supplemental_claim/edit_spec.rb | 65 + .../vha_hlr_sc_enter_no_decision_date_spec.rb | 103 +- spec/feature/non_comp/dispositions_spec.rb | 46 +- spec/feature/non_comp/reviews_spec.rb | 118 +- spec/feature/queue/ama_queue_workflow_spec.rb | 40 +- .../queue/scm_judge_assignment_spec.rb | 1 + spec/feature/reader/logs_spec.rb | 81 +- .../test_docket_case_seeds_spec.rb | 181 ++ .../jobs/incomplete_distributions_job_spec.rb | 5 + ...ush_priority_appeals_to_judges_job_spec.rb | 30 +- spec/mailers/dispatch_mailer_spec.rb | 2 +- spec/models/business_line_spec.rb | 66 + spec/models/case_distribution_lever_spec.rb | 6 +- spec/models/claim_review_spec.rb | 31 + .../by_docket_date_distribution_spec.rb | 5 + spec/models/distribution_spec.rb | 5 + spec/models/docket_coordinator_spec.rb | 1 + spec/models/docket_spec.rb | 195 +- .../dockets/hearing_request_docket_spec.rb | 144 +- spec/models/dockets/legacy_docket_spec.rb | 28 + ...grant_effectuation_task_serializer_spec.rb | 3 + .../decision_review_task_serializer_spec.rb | 4 + .../veteran_record_request_serializer_spec.rb | 1 + .../models/tasks/decision_review_task_spec.rb | 2 + spec/models/user_spec.rb | 42 + spec/models/vha_business_line_spec.rb | 5 +- spec/seeds/users_spec.rb | 2 +- .../updater_spec.rb | 276 ++ spec/support/intake_helpers.rb | 46 +- 238 files changed, 14993 insertions(+), 3364 deletions(-) create mode 100644 app/controllers/test_docket_seeds_controller.rb create mode 100644 app/controllers/test_seeds_controller.rb create mode 100644 app/models/issue_modification_request.rb create mode 100644 app/queries/appeals_non_priority_ready_for_distribution.rb create mode 100644 app/serializers/intake/issue_modification_request_serializer.rb create mode 100644 app/services/issue_modification_requests/updater.rb create mode 100644 app/views/test/seeds.html.erb create mode 100644 client/app/caseDistribution/components/ExcludeDocketLever.jsx create mode 100644 client/app/intake/actions/issueModificationRequest.js create mode 100644 client/app/intake/components/CancelPendingRequestIssueModal.jsx create mode 100644 client/app/intake/components/ConfirmPendingRequestIssueModal.jsx create mode 100644 client/app/intake/components/IssueModificationList.jsx create mode 100644 client/app/intake/components/IssueModificationRequest.jsx create mode 100644 client/app/intake/components/IssueModificationRow.jsx create mode 100644 client/app/intake/components/IssueModificationRow.stories.js create mode 100644 client/app/intake/util/issueModificationRequests.js create mode 100644 client/app/intakeEdit/components/PendingIssueModificationRequestBanner.jsx create mode 100644 client/app/intakeEdit/components/RequestCommonComponents/CurrentIssue.jsx create mode 100644 client/app/intakeEdit/components/RequestCommonComponents/IssueDescription.jsx create mode 100644 client/app/intakeEdit/components/RequestCommonComponents/IssueTypeSelector.jsx create mode 100644 client/app/intakeEdit/components/RequestCommonComponents/PriorDecisionDateAlert.jsx create mode 100644 client/app/intakeEdit/components/RequestCommonComponents/PriorDecisionDateSelector.jsx create mode 100644 client/app/intakeEdit/components/RequestCommonComponents/RequestIssueFormWrapper.jsx create mode 100644 client/app/intakeEdit/components/RequestCommonComponents/RequestIssueStatus.jsx create mode 100644 client/app/intakeEdit/components/RequestCommonComponents/RequestReason.jsx create mode 100644 client/app/intakeEdit/components/RequestIssueAdditionModal.jsx create mode 100644 client/app/intakeEdit/components/RequestIssueModals.stories.js create mode 100644 client/app/intakeEdit/components/RequestIssueModificationModal.jsx create mode 100644 client/app/intakeEdit/components/RequestIssueRemovalModal.jsx create mode 100644 client/app/intakeEdit/components/RequestIssueWithdrawalModal.jsx create mode 100644 client/app/styles/caseDistribution/_test_seeds.scss create mode 100644 client/app/testSeeds/components/CustomSeeds.jsx create mode 100644 client/app/testSeeds/components/SeedsBannerDisplay.jsx create mode 100644 client/app/testSeeds/components/TestSeedsWrapper.jsx create mode 100644 client/app/testSeeds/index.jsx create mode 100644 client/app/testSeeds/pages/TestSeedsApp.jsx create mode 100644 client/app/testSeeds/reducers/root.js create mode 100644 client/app/testSeeds/reducers/seeds/seedsActionTypes.js create mode 100644 client/app/testSeeds/reducers/seeds/seedsActions.js create mode 100644 client/app/testSeeds/reducers/seeds/seedsReducer.js create mode 100644 client/app/util/NetworkUtil.js create mode 100644 client/constants/CUSTOM_SEEDS.json create mode 100644 client/constants/TEST_SEEDS.json create mode 100644 client/test/app/caseDistribution/components/ExcludeDocketLever.test.js create mode 100644 client/test/app/caseDistribution/components/ExclusionTable.test.js create mode 100644 client/test/app/intake/components/CancelPendingRequestIssueModal.test.js create mode 100644 client/test/app/intake/components/ConfirmPendingRequestIssueModal.test.js create mode 100644 client/test/app/intake/components/IssueModificationList.test.js create mode 100644 client/test/app/testSeeds/components/CustomSeeds.test.js create mode 100644 client/test/app/testSeeds/pages/TestSeedsApp.test.js create mode 100644 client/test/app/testSeeds/reducers/root.test.js create mode 100644 client/test/app/testSeeds/reducers/seeds/seedsActions.test.js create mode 100644 client/test/app/testSeeds/reducers/seeds/seedsReducer.test.js create mode 100644 client/test/app/util/NetworkUtil-test.js create mode 100644 client/test/data/intakeEdit/store.js create mode 100644 client/test/data/issueModificationListProps.js create mode 100644 db/migrate/20240429215736_create_issue_modification_request.rb create mode 100644 db/migrate/20240613202232_update_control_group_data_type_in_case_distribution_lever.rb create mode 100644 db/seeds/demo_ama_aod_hearing_data.rb create mode 100644 db/seeds/demo_ama_docket_goals_lever_test_data.rb create mode 100644 db/seeds/demo_ama_non_aod_hearing_data.rb create mode 100644 db/seeds/demo_direct_reviews_data.rb create mode 100644 db/seeds/demo_docket_priority_lever_test_data.rb create mode 100644 db/seeds/demo_legacy_cases_data.rb create mode 100644 db/seeds/issue_modification_request.rb create mode 100644 public/sample_custom_seeds.csv create mode 100644 spec/controllers/supplemental_claims_controller_spec.rb create mode 100644 spec/controllers/test_docket_seeds_controller_spec.rb create mode 100644 spec/factories/issue_modification_request.rb create mode 100644 spec/feature/intake/issue_modification_request_spec.rb create mode 100644 spec/feature/intake/reassign_cases_to_camo_spec.rb create mode 100644 spec/feature/test_seeds/test_docket_case_seeds/test_docket_case_seeds_spec.rb create mode 100644 spec/services/issue_modification_requests/updater_spec.rb diff --git a/Gemfile b/Gemfile index 0b6822d2c27..17eec027d43 100644 --- a/Gemfile +++ b/Gemfile @@ -68,6 +68,7 @@ gem "request_store" gem "roo", "~> 2.7" gem "rswag-api" gem "rswag-ui" +gem "ruby_claim_evidence_api", git: "https://github.com/department-of-veterans-affairs/ruby_claim_evidence_api.git", ref: "fed623802afe7303f4b8b5fe27cff0e903699873" # Use SCSS for stylesheets gem "sass-rails", "~> 5.0" # Error reporting to Sentry diff --git a/Gemfile.lock b/Gemfile.lock index 82df5ebe5a5..2239aa22953 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -65,6 +65,20 @@ GIT nokogiri (>= 1.11.0.rc4) savon (~> 2.12) +GIT + remote: https://github.com/department-of-veterans-affairs/ruby_claim_evidence_api.git + revision: fed623802afe7303f4b8b5fe27cff0e903699873 + ref: fed623802afe7303f4b8b5fe27cff0e903699873 + specs: + ruby_claim_evidence_api (0.0.1) + activesupport + base64 + faraday + faraday-multipart + httpi + railties + webmock (~> 3.6.2) + GIT remote: https://github.com/department-of-veterans-affairs/sniffybara.git revision: 351560b5789ca638ba7c9b093c2bb1a9a6fda4b3 @@ -1440,6 +1454,7 @@ GEM aws-sigv4 (1.8.0) aws-eventstream (~> 1, >= 1.0.2) backport (1.2.0) + base64 (0.2.0) benchmark-ips (2.7.2) bootsnap (1.7.5) msgpack (~> 1.0) @@ -1580,6 +1595,8 @@ GEM multipart-post (>= 1.2, < 3) faraday-http-cache (2.4.1) faraday (>= 0.8) + faraday-multipart (1.0.4) + multipart-post (~> 2) faraday_middleware (0.13.1) faraday (>= 0.7.4, < 1.0) fast_jsonapi (1.5) @@ -2115,6 +2132,7 @@ DEPENDENCIES ruby-debug-ide ruby-oci8 (~> 2.2) ruby-prof (~> 1.4) + ruby_claim_evidence_api! sass-rails (~> 5.0) scss_lint sentry-raven @@ -2139,4 +2157,4 @@ DEPENDENCIES ziptz BUNDLED WITH - 2.4.17 + 2.4.22 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 00ac5a7adba..c34519195e4 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -161,6 +161,14 @@ def case_distribution_url } end + def test_seeds_url + { + title: "Test Seeds", + link: "/test/seeds", + sort_order: 7 + } + end + def hearing_application_url { title: "Hearings", @@ -210,14 +218,30 @@ def manage_users_menu_item def admin_menu_items admin_urls = [] - admin_urls.concat(manage_teams_menu_items) if current_user&.administered_teams&.any? - admin_urls.push(manage_users_menu_item) if current_user&.can_view_user_management? - admin_urls.push(case_distribution_url) if current_user&.organizations&.any?(&:users_can_view_levers?) + add_team_management_items(admin_urls) + add_user_management_items(admin_urls) + add_case_distribution_item(admin_urls) + + admin_urls.flatten + end + def add_team_management_items(admin_urls) if current_user&.can_view_team_management? || current_user&.can_view_judge_team_management? admin_urls.unshift(manage_all_teams_menu_item) end - admin_urls.flatten + end + + def add_user_management_items(admin_urls) + admin_urls.concat(manage_teams_menu_items) if current_user&.administered_teams&.any? + admin_urls.push(manage_users_menu_item) if current_user&.can_view_user_management? + end + + def add_case_distribution_item(admin_urls) + admin_urls.push(case_distribution_url) if current_user&.organizations&.any?(&:users_can_view_levers?) + end + + def add_test_seeds_item(admin_urls) + admin_urls.push(test_seeds_url) if current_user&.organizations&.any?(&:users_can_view_levers?) end def dropdown_urls diff --git a/app/controllers/case_distribution_levers_tests_controller.rb b/app/controllers/case_distribution_levers_tests_controller.rb index c3d2502939b..b13763b071d 100644 --- a/app/controllers/case_distribution_levers_tests_controller.rb +++ b/app/controllers/case_distribution_levers_tests_controller.rb @@ -26,6 +26,20 @@ def run_demo_aod_hearing_seeds head :ok end + def run_demo_ama_docket_goals + Rake::Task["db:seed:demo_ama_docket_goals_lever_test_data"].reenable + Rake::Task["db:seed:demo_ama_docket_goals_lever_test_data"].invoke + + head :ok + end + + def run_demo_docket_priority + Rake::Task["db:seed:demo_docket_priority_lever_test_data"].reenable + Rake::Task["db:seed:demo_docket_priority_lever_test_data"].invoke + + head :ok + end + def appeals_ready_to_distribute csv_data = AppealsReadyForDistribution.process @@ -39,6 +53,19 @@ def appeals_ready_to_distribute send_data csv_data, filename: filename end + def appeals_non_priority_ready_to_distribute + csv_data = AppealsNonPriorityReadyForDistribution.process + + # Get the current date and time for dynamic filename + current_datetime = Time.zone.now.strftime("%Y%m%d-%H%M") + + # Set dynamic filename with current date and time + filename = "AMA_Non_priority_distributable_#{current_datetime}.csv" + + # Send CSV as a response with dynamic filename + send_data csv_data, filename: filename + end + def appeals_distributed # change this to the correct class csv_data = AppealsDistributed.process diff --git a/app/controllers/claim_review_controller.rb b/app/controllers/claim_review_controller.rb index d4dc84d5a56..c4311485a2c 100644 --- a/app/controllers/claim_review_controller.rb +++ b/app/controllers/claim_review_controller.rb @@ -28,7 +28,11 @@ def edit end def update - if request_issues_update.perform! + if issues_modification_request_updater.non_admin_actions? + process_and_render_issue_non_admin_issue_modification_requests + elsif issues_modification_request_updater.admin_actions? + process_and_render_issue_admin_issue_modification_requests + elsif request_issues_update.perform! render_success else render json: { error_code: request_issues_update.error_code }, status: :unprocessable_entity @@ -56,6 +60,14 @@ def source_type fail "Must override source_type" end + def issues_modification_request_updater + @issues_modification_request_updater ||= IssueModificationRequests::Updater.new( + user: current_user, + review: claim_review, + issue_modifications_data: params[:issue_modification_requests] + ) + end + def request_issues_update @request_issues_update ||= RequestIssuesUpdate.new( user: current_user, @@ -133,15 +145,23 @@ def removed_issues end def review_edited_message - "You have successfully " + [added_issues, removed_issues, withdrawn_issues].compact.to_sentence + "." + "You have successfully #{[added_issues, removed_issues, withdrawn_issues].compact.to_sentence}." end def vha_edited_decision_date_message COPY::VHA_ADD_DECISION_DATE_TO_ISSUE_SUCCESS_MESSAGE end - def vha_established_message - "You have successfully established #{claimant_name}'s #{claim_review.class.review_title}" + def vha_pending_reviews_message + "#{claimant_name}'s #{claim_review.class.review_title} was saved." + end + + def vha_edited_title + "You have successfully edited #{claimant_name}'s #{claim_review.class.review_title}" + end + + def vha_edited_message + "The claim has been modified." end def claimant_name @@ -158,27 +178,53 @@ def vha_flash_message request_issues_update.removed_or_withdrawn_issues) .select { |issue| issue.decision_date.blank? && !issue.withdrawn? } - if issues_without_decision_date.empty? - vha_established_message + if claim_review.pending_issue_modification_requests.any? + vha_pending_reviews_message_hash + elsif issues_without_decision_date.empty? + { title: vha_edited_title, message: vha_edited_message } elsif request_issues_update.edited_issues.any? - vha_edited_decision_date_message + { title: "Edit Completed", message: vha_edited_decision_date_message } else - review_edited_message + decisions_message_hash_builder(vha_edited_message, review_edited_message) end end def set_flash_success_message - flash[:edited] = if request_issues_update.after_issues.empty? - decisions_removed_message + flash[:custom] = if request_issues_update.after_issues.empty? + decisions_removed_hash elsif (request_issues_update.after_issues - request_issues_update.withdrawn_issues).empty? - review_withdrawn_message - elsif claim_review.benefit_type == "vha" + decisions_withdrawn_hash + elsif claim_review.vha_claim? vha_flash_message else - review_edited_message + { title: "Edit Completed", message: review_edited_message } end end + def decisions_message_hash_builder(vha_message, default_message) + if claim_review.vha_claim? + { title: vha_edited_title, message: vha_message } + else + { title: "Edit Completed", message: default_message } + end + end + + def decisions_removed_hash + decisions_message_hash_builder("The claim has been removed.", decisions_removed_message) + end + + def decisions_withdrawn_hash + decisions_message_hash_builder("The claim has been withdrawn.", review_withdrawn_message) + end + + def vha_pending_reviews_message_hash + if current_user.vha_business_line_admin_user? + { title: vha_edited_title, message: vha_edited_message } + else + { title: "You have successfully submitted a request.", message: vha_pending_reviews_message } + end + end + def decisions_removed_message "You have successfully removed #{claim_review.class.review_title} for #{claimant_name} (ID: #{claim_review.veteran.ssn})." @@ -203,4 +249,32 @@ def perform_ep_update!(epe) ep_update.perform! ep_update end + + def process_and_render_issue_non_admin_issue_modification_requests + issues_modification_request_updater.non_admin_process! + render_success + rescue StandardError => error + render_error(error) + end + + def process_and_render_issue_admin_issue_modification_requests + # If there are no approvals, then we can just deny the requests. We do not need to process request_issues_updates + if issues_modification_request_updater.admin_approvals? + if request_issues_update.can_be_performed? + issues_modification_request_updater.admin_process! + if request_issues_update.perform! + return render_success + end + end + + # Fallback return error since it fell through + render json: { error_code: request_issues_update.error_code }, status: :unprocessable_entity + else + # Only denied requests to just run the process and return success unless it errors + issues_modification_request_updater.admin_process! + render_success + end + rescue StandardError => error + render_error(error) + end end diff --git a/app/controllers/decision_reviews_controller.rb b/app/controllers/decision_reviews_controller.rb index 8a051542a48..6fd27467dfa 100644 --- a/app/controllers/decision_reviews_controller.rb +++ b/app/controllers/decision_reviews_controller.rb @@ -15,6 +15,9 @@ class DecisionReviewsController < ApplicationController :in_progress_tasks, :in_progress_tasks_type_counts, :in_progress_tasks_issue_type_counts, + :pending_tasks, + :pending_tasks_type_counts, + :pending_tasks_issue_type_counts, :completed_tasks, :completed_tasks_type_counts, :completed_tasks_issue_type_counts, @@ -29,7 +32,8 @@ class DecisionReviewsController < ApplicationController "issueCountColumn" => "issue_count", "issueTypesColumn" => "issue_types_lower", "daysWaitingColumn" => "tasks.assigned_at", - "completedDateColumn" => "tasks.closed_at" + "completedDateColumn" => "tasks.closed_at", + "pendingIssueModificationRequests" => "pending_issue_count" }.freeze def index @@ -68,6 +72,10 @@ def history end def update + if task.appeal.pending_issue_modification_requests.any? + return render json: { error_uuid: error_uuid, error_code: "pendingModificationRequests" }, status: :bad_request + end + if task.complete_with_payload!(decision_issue_params, decision_date, current_user) business_line.tasks.reload render json: { task_filter_details: task_filter_details }, status: :ok @@ -124,6 +132,9 @@ def task_filter_details when :incomplete task_filter_hash[:incomplete] = incomplete_tasks_type_counts task_filter_hash[:incomplete_issue_types] = incomplete_tasks_issue_type_counts + when :pending + task_filter_hash[:pending] = pending_tasks_type_counts + task_filter_hash[:pending_issue_types] = pending_tasks_issue_type_counts when :in_progress task_filter_hash[:in_progress] = in_progress_tasks_type_counts task_filter_hash[:in_progress_issue_types] = in_progress_tasks_issue_type_counts @@ -180,6 +191,7 @@ def queue_tasks tasks = case tab_name when "incomplete" then incomplete_tasks(pagination_query_params(sort_by_column)) + when "pending" then pending_tasks(pagination_query_params(sort_by_column)) when "in_progress" then in_progress_tasks(pagination_query_params(sort_by_column)) when "completed" then completed_tasks(pagination_query_params(sort_by_column)) when nil diff --git a/app/controllers/intakes_controller.rb b/app/controllers/intakes_controller.rb index 37e21cb3ba0..ca08b861167 100644 --- a/app/controllers/intakes_controller.rb +++ b/app/controllers/intakes_controller.rb @@ -99,6 +99,7 @@ def index_props userDisplayName: current_user.display_name, userCanIntakeAppeals: current_user.can_intake_appeals?, userCanEditIntakeIssues: current_user.can_edit_intake_issues?, + userIsVhaAdmin: current_user.vha_business_line_admin_user?, serverIntake: intake_ui_hash, dropdownUrls: dropdown_urls, applicationUrls: application_urls, diff --git a/app/controllers/test_docket_seeds_controller.rb b/app/controllers/test_docket_seeds_controller.rb new file mode 100644 index 00000000000..207977c6439 --- /dev/null +++ b/app/controllers/test_docket_seeds_controller.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +class TestDocketSeedsController < ApplicationController + before_action :check_environment # , :verify_access + # before_action :current_user, only: [:reset_all_appeals] + + def seed_dockets + JSON.parse(request.body.read).each do |row_entry| + task_name = Constants.TEST_SEEDS.to_h[row_entry["seed_type"].to_sym] + ENV["SEED_COUNT"] = row_entry["seed_count"].to_s + ENV["DAYS_AGO"] = row_entry["days_ago"].to_s + ENV["JUDGE_CSS_ID"] = row_entry["judge_css_id"].to_s + + Rake::Task[task_name].reenable + Rake::Task[task_name].invoke + + ENV.delete("SEED_COUNT") + ENV.delete("DAYS_AGO") + ENV.delete("JUDGE_CSS_ID") + end + + head :ok + end + + def reset_all_appeals + RequestStore[:current_user] = current_user + DistributionTask.where(status: "assigned").map { |t| t.update!(status: "on_hold") } + VACOLS::Case.where(bfcurloc: %w[81 83]).map { |c| c.update!(bfcurloc: "testing") } + + head :ok + end + + private + + # def verify_access ##future work + # return true if current_user&.organizations && current_user.organizations.any?(&:users_can_view_levers?) + + # session["return_to"] = request.original_url + # redirect_to "/unauthorized" + # end + + def check_environment + return true if Rails.env.development? || Rails.deploy_env?(:demo) || Rails.deploy_env?(:uat) + + redirect_to "/unauthorized" + end +end diff --git a/app/controllers/test_seeds_controller.rb b/app/controllers/test_seeds_controller.rb new file mode 100644 index 00000000000..a5ca03fc54a --- /dev/null +++ b/app/controllers/test_seeds_controller.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require "csv" + +class Test::TestSeedsController < ApplicationController + before_action :check_environment + before_action :verify_access, only: [:seeds] + before_action :authorize_admin, only: [:seeds] + + def seeds + # seeds + render "/test/seeds" + end + + private + + def check_environment + return true if Rails.env.development? + return true if Rails.deploy_env?(:demo) + + redirect_to "/unauthorized" + end + + def authorize_admin + error = ["UNAUTHORIZED"] + + resp = { + status_code: 500, + message: error, + user_is_an_acd_admin: false + } + render json: resp unless CDAControlGroup.singleton.user_is_admin?(current_user) + end + + def verify_access + return true if current_user&.organizations && current_user.organizations.any?(&:users_can_view_levers?) + + session["return_to"] = request.original_url + redirect_to "/unauthorized" + end +end diff --git a/app/jobs/push_priority_appeals_to_judges_job.rb b/app/jobs/push_priority_appeals_to_judges_job.rb index e042610c08a..6cf23f80928 100644 --- a/app/jobs/push_priority_appeals_to_judges_job.rb +++ b/app/jobs/push_priority_appeals_to_judges_job.rb @@ -60,9 +60,7 @@ def slack_report # rubocop:disable Metrics/AbcSize, Metrics/MethodLength docket_coordinator.dockets.each_pair do |sym, docket| report << "*Number of #{sym} appeals _not_ distributed*: #{docket.count(priority: true, ready: true)}" end - unless disable_legacy? - report << "*Number of Legacy Hearing Non Genpop appeals _not_ distributed*: #{legacy_not_genpop_count}" - end + report << "*Number of Legacy Hearing Non Genpop appeals _not_ distributed*: #{legacy_not_genpop_count}" report << "" report << "*Debugging information*" @@ -184,10 +182,6 @@ def use_by_docket_date? FeatureToggle.enabled?(:acd_distribute_by_docket_date, user: RequestStore.store[:current_user]) end - def disable_legacy? - FeatureToggle.enabled?(:acd_disable_legacy_distributions, user: RequestStore.store[:current_user]) - end - def legacy_not_genpop_count docket_coordinator.dockets[:legacy].not_genpop_priority_count end diff --git a/app/mailers/dispatch_mailer.rb b/app/mailers/dispatch_mailer.rb index 87da8af8e23..0c026bfca65 100644 --- a/app/mailers/dispatch_mailer.rb +++ b/app/mailers/dispatch_mailer.rb @@ -6,7 +6,7 @@ ## # rubocop:disable Rails/ApplicationMailer class DispatchMailer < ActionMailer::Base - default from: "Board of Veterans' Appeals " + default from: "Board of Veterans' Appeals " layout "dispatch_mailer" helper VirtualHearings::LinkHelper diff --git a/app/models/appeal.rb b/app/models/appeal.rb index 51ba29ecbcf..00876e8100e 100644 --- a/app/models/appeal.rb +++ b/app/models/appeal.rb @@ -909,6 +909,10 @@ def create_business_line_tasks! end end + def task_in_progress? + nil + end + def stuck? AppealsWithNoTasksOrAllTasksOnHoldQuery.new.ama_appeal_stuck?(self) end diff --git a/app/models/case_distribution_lever.rb b/app/models/case_distribution_lever.rb index 8d99040c380..6db4b0cbd8e 100644 --- a/app/models/case_distribution_lever.rb +++ b/app/models/case_distribution_lever.rb @@ -22,7 +22,9 @@ class CaseDistributionLever < ApplicationRecord #{Constants.DISTRIBUTION.ama_hearing_case_aod_affinity_days} #{Constants.DISTRIBUTION.cavc_affinity_days} #{Constants.DISTRIBUTION.ama_evidence_submission_docket_time_goals} - #{Constants.DISTRIBUTION.ama_hearings_docket_time_goals} + #{Constants.DISTRIBUTION.ama_hearing_docket_time_goals} + #{Constants.DISTRIBUTION.ama_hearing_start_distribution_prior_to_goals} + #{Constants.DISTRIBUTION.ama_evidence_submission_start_distribution_prior_to_goals} ).freeze FLOAT_LEVERS = %W( @@ -31,6 +33,11 @@ class CaseDistributionLever < ApplicationRecord #{Constants.DISTRIBUTION.nod_adjustment} ).freeze + BOOLEAN_LEVERS = %W( + #{Constants.DISTRIBUTION.disable_legacy_priority} + #{Constants.DISTRIBUTION.disable_legacy_non_priority} + ).freeze + def history_value if combination_lever? combination_value @@ -185,6 +192,8 @@ def method_missing_value(name) Integer(lever) elsif FLOAT_LEVERS.include?(name) Float(lever) + elsif BOOLEAN_LEVERS.include?(name) + ActiveModel::Type::Boolean.new.cast(lever) else lever end diff --git a/app/models/claim_review.rb b/app/models/claim_review.rb index 261bc9c09f7..150e5977318 100644 --- a/app/models/claim_review.rb +++ b/app/models/claim_review.rb @@ -126,8 +126,10 @@ def create_business_line_tasks! end def redirect_url - if benefit_type == "vha" && request_issues_without_decision_dates? + if vha_claim? && request_issues_without_decision_dates? "#{business_line.tasks_url}?tab=incomplete" + elsif vha_claim? && pending_issue_modification_requests.any? + "#{business_line.tasks_url}?tab=pending" else business_line.tasks_url end @@ -206,6 +208,10 @@ def active_status? active? end + def vha_claim? + benefit_type == "vha" + end + def search_table_ui_hash { caseflow_veteran_id: claim_veteran&.id, @@ -305,6 +311,10 @@ def sct_appeal? false end + def task_in_progress? + tasks.any?(&:active?) + end + private def cleared_end_products diff --git a/app/models/concerns/by_docket_date_distribution.rb b/app/models/concerns/by_docket_date_distribution.rb index 851858c133a..2b1b787f725 100644 --- a/app/models/concerns/by_docket_date_distribution.rb +++ b/app/models/concerns/by_docket_date_distribution.rb @@ -32,12 +32,10 @@ def requested_distribution priority_rem = priority_target.clamp(0, @rem) distribute_priority_appeals_from_all_dockets_by_age_to_limit(priority_rem, style: "request") - unless FeatureToggle.enabled?(:acd_disable_nonpriority_distributions, user: RequestStore.store[:current_user]) - # Distribute the oldest nonpriority appeals from any docket if we haven't distributed {batch_size} appeals - # @nonpriority_iterations guards against an infinite loop if not enough cases are ready to distribute - until @rem <= 0 || @nonpriority_iterations >= MAX_NONPRIORITY_ITERATIONS - distribute_nonpriority_appeals_from_all_dockets_by_age_to_limit(@rem) - end + # Distribute the oldest nonpriority appeals from any docket if we haven't distributed {batch_size} appeals + # @nonpriority_iterations guards against an infinite loop if not enough cases are ready to distribute + until @rem <= 0 || @nonpriority_iterations >= MAX_NONPRIORITY_ITERATIONS + distribute_nonpriority_appeals_from_all_dockets_by_age_to_limit(@rem) end @appeals end @@ -59,7 +57,7 @@ def distribute_nonpriority_appeals_from_all_dockets_by_age_to_limit(limit, style end end - # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + # rubocop:disable Metrics/MethodLength def ama_statistics priority_counts = { count: priority_count } nonpriority_counts = { count: nonpriority_count } @@ -69,10 +67,8 @@ def ama_statistics nonpriority_counts[sym] = docket.count(priority: false, ready: true) end - unless FeatureToggle.enabled?(:acd_disable_legacy_distributions, user: RequestStore.store[:current_user]) - priority_counts[:legacy_hearing_tied_to] = legacy_hearing_priority_count(judge) - nonpriority_counts[:legacy_hearing_tied_to] = legacy_hearing_nonpriority_count(judge) - end + priority_counts[:legacy_hearing_tied_to] = legacy_hearing_priority_count(judge) + nonpriority_counts[:legacy_hearing_tied_to] = legacy_hearing_nonpriority_count(judge) nonpriority_counts[:iterations] = @nonpriority_iterations @@ -80,8 +76,6 @@ def ama_statistics settings = {} feature_toggles = [ - :acd_disable_legacy_distributions, - :acd_disable_nonpriority_distributions, :specialty_case_team_distribution ] feature_toggles.each do |sym| @@ -110,7 +104,7 @@ def ama_statistics #{error.class}: #{error.message}, #{error.backtrace.first}" } end - # rubocop:enable Metrics/MethodLength, Metrics/AbcSize + # rubocop:enable Metrics/MethodLength def ama_distributed_cases_tied_to_ineligible_judges @appeals.filter_map do |appeal| diff --git a/app/models/concerns/distribution_concern.rb b/app/models/concerns/distribution_concern.rb index 82efe6006e1..0d113f69985 100644 --- a/app/models/concerns/distribution_concern.rb +++ b/app/models/concerns/distribution_concern.rb @@ -64,7 +64,7 @@ def cancel_previous_judge_assign_task(appeal, judge_id) # rubocop:disable Metrics/MethodLength # :reek:FeatureEnvy def create_sct_appeals(appeals_args, limit) - appeals = appeals(appeals_args) + appeals = ready_priority_nonpriority_appeals(appeals_args) .limit(limit) .includes(:request_issues) diff --git a/app/models/concerns/distribution_scopes.rb b/app/models/concerns/distribution_scopes.rb index ffa07fb72a9..f256c7cbc08 100644 --- a/app/models/concerns/distribution_scopes.rb +++ b/app/models/concerns/distribution_scopes.rb @@ -19,14 +19,15 @@ def priority include_aod_motions .where("advance_on_docket_motions.created_at > appeals.established_at") .where("advance_on_docket_motions.granted = ?", true) - .or(include_aod_motions.where("people.date_of_birth <= ?", 75.years.ago)) + .or(include_aod_motions.where("people.date_of_birth <= ? OR appeals.aod_based_on_age = ?", 75.years.ago, true)) .or(include_aod_motions.where("appeals.stream_type = ?", Constants.AMA_STREAM_TYPES.court_remand)) .group("appeals.id") end def nonpriority include_aod_motions - .where("people.date_of_birth > ? or people.date_of_birth is null", 75.years.ago) + .where("people.date_of_birth > ? or (appeals.aod_based_on_age in (?) AND people.date_of_birth is null)", + 75.years.ago, [false, nil]) .where.not("appeals.stream_type = ?", Constants.AMA_STREAM_TYPES.court_remand) .group("appeals.id") .having("count(case when advance_on_docket_motions.granted "\ @@ -122,8 +123,8 @@ def most_recent_hearings end def tied_to_distribution_judge(judge) - with_appeal_affinities - .where(hearings: { disposition: "held", judge_id: judge.id }) + with_appeal_affinities.where(hearings: { disposition: "held", judge_id: judge.id }) + .or(with_appeal_affinities.where(original_judge_task: { assigned_to_id: judge.id })) end def tied_to_ineligible_judge diff --git a/app/models/decision_review.rb b/app/models/decision_review.rb index 988c1c49406..7e1306187f4 100644 --- a/app/models/decision_review.rb +++ b/app/models/decision_review.rb @@ -10,6 +10,7 @@ class DecisionReview < CaseflowRecord attr_reader :saving_review has_many :request_issues, as: :decision_review, dependent: :destroy + has_many :issue_modification_requests, as: :decision_review, dependent: :destroy has_many :claimants, as: :decision_review, dependent: :destroy has_many :request_decision_issues, through: :request_issues has_many :decision_issues, as: :decision_review, dependent: :destroy @@ -263,6 +264,10 @@ def active_nonrating_request_issues .where.not(id: request_issues.map(&:id)) end + def pending_issue_modification_requests + issue_modification_requests.includes(:request_issue, :requestor, :decider).select(&:assigned?) + end + # do not confuse ui_hash with serializer. ui_hash for intake and intakeEdit. serializer for work queue. def serializer_class ::WorkQueue::DecisionReviewSerializer diff --git a/app/models/distribution.rb b/app/models/distribution.rb index 6b5479f377e..2568a5582f1 100644 --- a/app/models/distribution.rb +++ b/app/models/distribution.rb @@ -92,8 +92,6 @@ def judge_tasks end def judge_legacy_tasks - return [] if FeatureToggle.enabled?(:acd_disable_legacy_distributions, user: RequestStore.store[:current_user]) - legacy_tasks = QueueRepository.tasks_for_user(judge.css_id) @judge_legacy_tasks ||= legacy_tasks.select { |task| task.assigned_to_attorney_date.nil? } diff --git a/app/models/docket.rb b/app/models/docket.rb index 389bcf5498a..dcc314580af 100644 --- a/app/models/docket.rb +++ b/app/models/docket.rb @@ -5,6 +5,9 @@ class Docket include DistributionConcern include DistributionScopes + PRIORITY = "priority" + NON_PRIORITY = "non_priority" + def docket_type fail Caseflow::Error::MustImplementInSubclass end @@ -32,6 +35,23 @@ def appeals(priority: nil, genpop: nil, ready: nil, judge: nil) scope.order("appeals.receipt_date") end + + def ready_priority_nonpriority_appeals(priority: false, ready: true, judge: nil, genpop: nil) + priority_status = priority ? PRIORITY : NON_PRIORITY + appeals = appeals(priority: priority, ready: ready, genpop: genpop, judge: judge) + lever_item = "disable_ama_#{priority_status}_#{docket_type.downcase}" + docket_type_lever = CaseDistributionLever.find_by_item(lever_item) + docket_type_lever_value = docket_type_lever ? CaseDistributionLever.public_send(lever_item) : nil + + if docket_type_lever_value == "true" + appeals.none + elsif priority_status == NON_PRIORITY && + start_distribution_prior_to_goal&.is_toggle_active && calculate_days_for_time_goal_with_prior_to_goal > 0 + appeals.where("appeals.receipt_date <= ?", calculate_days_for_time_goal_with_prior_to_goal.days.ago) + else + appeals + end + end # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def count(priority: nil, ready: nil) @@ -60,23 +80,27 @@ def weight end def age_of_n_oldest_genpop_priority_appeals(num) - appeals(priority: true, ready: true).limit(num).map(&:ready_for_distribution_at) + ready_priority_nonpriority_appeals( + priority: true, + ready: true, + genpop: true + ).limit(num).map(&:ready_for_distribution_at) end def age_of_n_oldest_priority_appeals_available_to_judge(judge, num) - appeals(priority: true, ready: true, judge: judge).limit(num).map(&:receipt_date) + ready_priority_nonpriority_appeals(priority: true, ready: true, judge: judge).limit(num).map(&:receipt_date) end def age_of_n_oldest_nonpriority_appeals_available_to_judge(judge, num) - appeals(priority: false, ready: true, judge: judge).limit(num).map(&:receipt_date) + ready_priority_nonpriority_appeals(priority: false, ready: true, judge: judge).limit(num).map(&:receipt_date) end def age_of_oldest_priority_appeal @age_of_oldest_priority_appeal ||= if use_by_docket_date? - appeals(priority: true, ready: true).limit(1).first&.receipt_date + ready_priority_nonpriority_appeals(priority: true, ready: true).limit(1).first&.receipt_date else - appeals(priority: true, ready: true).limit(1).first&.ready_for_distribution_at + ready_priority_nonpriority_appeals(priority: true, ready: true).limit(1).first&.ready_for_distribution_at end end @@ -97,7 +121,12 @@ def distribute_appeals(distribution, priority: false, genpop: nil, limit: 1, sty query_args = { priority: priority, ready: true, genpop: genpop, judge: distribution.judge } appeals, sct_appeals = create_sct_appeals(query_args, limit) else - appeals = appeals(priority: priority, ready: true, genpop: genpop, judge: distribution.judge).limit(limit) + appeals = ready_priority_nonpriority_appeals( + priority: priority, + ready: true, + genpop: genpop, + judge: distribution.judge + ).limit(limit) sct_appeals = [] end @@ -132,6 +161,24 @@ def self.nonpriority_decisions_per_year .pluck(:id).size end + def calculate_days_for_time_goal_with_prior_to_goal + return 0 unless docket_time_goal > 0 + + docket_time_goal - Integer(start_distribution_prior_to_goal.value) + end + + def docket_time_goal + @docket_time_goal ||= begin + does_lever_exist = CaseDistributionLever.exists?(item: "ama_#{docket_type}_docket_time_goals") + does_lever_exist ? CaseDistributionLever.public_send("ama_#{docket_type}_docket_time_goals") : 0 + end + end + + def start_distribution_prior_to_goal + @start_distribution_prior_to_goal ||= + CaseDistributionLever.find_by(item: "ama_#{docket_type}_start_distribution_prior_to_goals") + end + private # :reek:ControlParameter diff --git a/app/models/docket_coordinator.rb b/app/models/docket_coordinator.rb index 7f7a7237332..1d01a87dc8e 100644 --- a/app/models/docket_coordinator.rb +++ b/app/models/docket_coordinator.rb @@ -9,10 +9,6 @@ def dockets hearing: HearingRequestDocket.new } - if FeatureToggle.enabled?(:acd_disable_legacy_distributions, user: RequestStore.store[:current_user]) - all_dockets.delete(:legacy) - end - @dockets ||= all_dockets end diff --git a/app/models/dockets/hearing_request_docket.rb b/app/models/dockets/hearing_request_docket.rb index 95340f9c4c7..1ff92b33313 100644 --- a/app/models/dockets/hearing_request_docket.rb +++ b/app/models/dockets/hearing_request_docket.rb @@ -5,17 +5,9 @@ def docket_type Constants.AMA_DOCKETS.hearing end - def ready_priority_appeals - appeals(priority: true, ready: true) - end - - def ready_nonpriority_appeals - appeals(priority: false, ready: true) - end - def age_of_n_oldest_genpop_priority_appeals(num) hearing_distribution_query( - base_relation: ready_priority_appeals.limit(num), genpop: "only_genpop" + base_relation: ready_priority_nonpriority_appeals(priority: true, ready: true).limit(num), genpop: "only_genpop" ).call.map(&:ready_for_distribution_at) end @@ -23,26 +15,39 @@ def age_of_n_oldest_genpop_priority_appeals(num) # but the judge that is passed in isn't relevant here def age_of_n_oldest_nonpriority_appeals_available_to_judge(judge, num) hearing_distribution_query( - base_relation: ready_nonpriority_appeals.limit(num), genpop: "only_genpop", judge: judge + base_relation: ready_priority_nonpriority_appeals( + priority: false, + ready: true, + judge: judge + ).limit(num), genpop: "only_genpop", judge: judge ).call.map(&:receipt_date) end # Hearing cases distinguish genpop from cases tied to a judge # Returns number of ready priority appeals that are not tied to a judge def genpop_priority_count - hearing_distribution_query(base_relation: ready_priority_appeals, genpop: "only_genpop").call.count + hearing_distribution_query( + base_relation: ready_priority_nonpriority_appeals( + priority: true, + ready: true + ), genpop: "only_genpop" + ).call.count end def age_of_n_oldest_priority_appeals_available_to_judge(judge, num) hearing_distribution_query( - base_relation: ready_priority_appeals.limit(num), genpop: "only_genpop", judge: judge + base_relation: ready_priority_nonpriority_appeals( + priority: true, + ready: true, + judge: judge + ).limit(num), genpop: "only_genpop", judge: judge ).call.flatten.map(&:receipt_date) end # rubocop:disable Lint/UnusedMethodArgument def distribute_appeals(distribution, priority: false, genpop: "any", limit: 1, style: "push") query_args = { priority: priority, ready: true, judge: distribution.judge } - base_relation = appeals(query_args).limit(limit) + base_relation = ready_priority_nonpriority_appeals(query_args).limit(limit) # setting genpop to "only_genpop" behind feature toggle as this module only processes AMA. genpop = "only_genpop" if use_by_docket_date? diff --git a/app/models/dockets/legacy_docket.rb b/app/models/dockets/legacy_docket.rb index 4550400694b..0a8c05cb5c9 100644 --- a/app/models/dockets/legacy_docket.rb +++ b/app/models/dockets/legacy_docket.rb @@ -57,14 +57,20 @@ def age_of_oldest_priority_appeal end def age_of_n_oldest_genpop_priority_appeals(num) + return [] unless ready_priority_nonpriority_legacy_appeals(priority: true) + LegacyAppeal.repository.age_of_n_oldest_genpop_priority_appeals(num) end def age_of_n_oldest_priority_appeals_available_to_judge(judge, num) + return [] unless ready_priority_nonpriority_legacy_appeals(priority: true) + LegacyAppeal.repository.age_of_n_oldest_priority_appeals_available_to_judge(judge, num) end def age_of_n_oldest_nonpriority_appeals_available_to_judge(judge, num) + return [] unless ready_priority_nonpriority_legacy_appeals(priority: false) + LegacyAppeal.repository.age_of_n_oldest_nonpriority_appeals_available_to_judge(judge, num) end @@ -74,13 +80,22 @@ def should_distribute?(distribution, style: "push", genpop: "any") (style == "request" && !JudgeTeam.for_judge(distribution.judge)&.ama_only_request) end + def ready_priority_nonpriority_legacy_appeals(priority: false) + value = priority ? CaseDistributionLever.disable_legacy_priority : CaseDistributionLever.disable_legacy_non_priority + !value + end + # rubocop:disable Metrics/ParameterLists def distribute_appeals(distribution, style: "push", priority: false, genpop: "any", limit: 1, range: nil) return [] unless should_distribute?(distribution, style: style, genpop: genpop) if priority + return [] unless ready_priority_nonpriority_legacy_appeals(priority: true) + distribute_priority_appeals(distribution, style: style, genpop: genpop, limit: limit) else + return [] unless ready_priority_nonpriority_legacy_appeals(priority: false) + distribute_nonpriority_appeals(distribution, style: style, genpop: genpop, limit: limit, range: range) end end @@ -88,6 +103,7 @@ def distribute_appeals(distribution, style: "push", priority: false, genpop: "an def distribute_priority_appeals(distribution, style: "push", genpop: "any", limit: 1) return [] unless should_distribute?(distribution, style: style, genpop: genpop) + return [] unless ready_priority_nonpriority_legacy_appeals(priority: true) LegacyAppeal.repository.distribute_priority_appeals(distribution.judge, genpop, limit).map do |record| next unless existing_distribution_case_may_be_redistributed?(record["bfkey"], distribution) @@ -106,7 +122,7 @@ def distribute_nonpriority_appeals(distribution, limit: 1, bust_backlog: false) return [] unless should_distribute?(distribution, style: style, genpop: genpop) - + return [] unless ready_priority_nonpriority_legacy_appeals(priority: false) return [] if !range.nil? && range <= 0 LegacyAppeal.repository.distribute_nonpriority_appeals( diff --git a/app/models/issue_modification_request.rb b/app/models/issue_modification_request.rb new file mode 100644 index 00000000000..8bb255a477c --- /dev/null +++ b/app/models/issue_modification_request.rb @@ -0,0 +1,162 @@ +# frozen_string_literal: true + +class IssueModificationRequest < CaseflowRecord + has_paper_trail on: [:update, :destroy] + + belongs_to :request_issue + belongs_to :decision_review, polymorphic: true + belongs_to :requestor, class_name: "User" + belongs_to :decider, class_name: "User", optional: true + + validates :status, :requestor, presence: true + + validate :only_one_assigned_issue_modification_request, if: :request_issue + validate :request_issue_exists_unless_addition + + before_save :set_decided_at + + enum status: { + assigned: "assigned", + approved: "approved", + denied: "denied", + cancelled: "cancelled" + } + + enum request_type: { + addition: "addition", + removal: "removal", + modification: "modification", + withdrawal: "withdrawal" + } + + def serialize + Intake::IssueModificationRequestSerializer.new(self).serializable_hash[:data][:attributes] + end + + def self.attributes_from_form_data(attributes) + { + request_issue_id: attributes[:request_issue_id], + request_type: attributes[:request_type].downcase, + request_reason: attributes[:request_reason], + benefit_type: attributes[:benefit_type], + decision_date: attributes[:decision_date], + decision_reason: attributes[:decision_reason], + nonrating_issue_category: attributes[:nonrating_issue_category], + nonrating_issue_description: attributes[:nonrating_issue_description], + status: attributes[:status].downcase, + withdrawal_date: attributes[:withdrawal_date] + } + end + + def self.create_from_params!(attributes, review, user) + unless attributes[:status].casecmp("assigned").zero? + fail( + Caseflow::Error::ErrorCreatingNewRequest, + message: COPY::ERROR_CREATING_NEW_REQUEST + ) + end + + create_attributes_hash = IssueModificationRequest.attributes_from_form_data(attributes) + .merge(decision_review: review, requestor: user) + + create!(create_attributes_hash) + end + + def edit_from_params!(attributes, user) + unless assigned? && non_admin_allowed_to_update?(user) + fail( + Caseflow::Error::ErrorModifyingExistingRequest, + message: COPY::ERROR_MODIFYING_EXISTING_REQUEST + ) + end + + update!(edited_attributes(attributes).merge(edited_at: Time.zone.now)) + end + + def cancel_from_params!(user) + unless assigned? && non_admin_allowed_to_update?(user) + fail( + Caseflow::Error::ErrorModifyingExistingRequest, + message: COPY::ERROR_MODIFYING_EXISTING_REQUEST + ) + end + + update!(status: "cancelled") + end + + def deny_request_from_params!(attributes, user) + unless admin_allowed_to_update?(user) + fail( + Caseflow::Error::ErrorDenyingExistingRequest, + message: COPY::ERROR_DECIDING_ISSUE_MODIFICATION_REQUEST + ) + end + + denial_attributes = { + decider: user, + status: :denied, + decision_reason: attributes[:decision_reason] + }.merge(edited_attributes(attributes)) + + update!(denial_attributes) + end + + def approve_request_from_params!(attributes, user) + unless admin_allowed_to_update?(user) + fail( + Caseflow::Error::ErrorApprovingExistingRequest, + message: COPY::ERROR_DECIDING_ISSUE_MODIFICATION_REQUEST + ) + end + + approve_attributes = { + decider: user, + status: :approved, + decision_reason: attributes[:decision_reason], + remove_original_issue: !!attributes[:remove_original_issue] + }.merge(edited_attributes(attributes)) + + update!(approve_attributes) + end + + private + + def only_one_assigned_issue_modification_request + if assigned? && request_issue.issue_modification_requests.assigned.where.not(id: id).exists? + fail( + Caseflow::Error::ErrorOpenModifyingExistingRequest, + message: COPY::ERROR_OPEN_MODIFICATION_EXISTING_REQUEST + ) + end + end + + def request_issue_exists_unless_addition + if !addition? && request_issue.nil? + errors.add(:request_issue, "must exist if request_type is not addition") + end + end + + def set_decided_at + if status_changed? && status_was == "assigned" && decider_id? + self.decided_at = Time.zone.now + end + end + + def non_admin_allowed_to_update?(user) + assigned? && requestor == user + end + + def admin_allowed_to_update?(user) + assigned? && user.vha_business_line_admin_user? + end + + def edited_attributes(attributes) + IssueModificationRequest.attributes_from_form_data(attributes).slice( + :nonrating_issue_category, + :decision_date, + :nonrating_issue_description, + :request_reason, + :withdrawal_date + ) + end +end diff --git a/app/models/organizations/business_line.rb b/app/models/organizations/business_line.rb index 2dea83c6861..5b43066bce2 100644 --- a/app/models/organizations/business_line.rb +++ b/app/models/organizations/business_line.rb @@ -41,6 +41,14 @@ def in_progress_tasks(pagination_params = {}) ).build_query end + def pending_tasks(pagination_params = {}) + QueryBuilder.new( + query_type: :pending, + query_params: pagination_params, + parent: self + ).build_query + end + def completed_tasks(pagination_params = {}) QueryBuilder.new( query_type: :completed, @@ -73,6 +81,14 @@ def completed_tasks_issue_type_counts QueryBuilder.new(query_type: :completed, parent: self).issue_type_count end + def pending_tasks_issue_type_counts + QueryBuilder.new(query_type: :pending, parent: self).issue_type_count + end + + def pending_tasks_type_counts + QueryBuilder.new(query_type: :pending, parent: self).task_type_count + end + def change_history_rows(filters = {}) QueryBuilder.new(query_params: filters, parent: self).change_history_rows end @@ -99,6 +115,9 @@ class QueryBuilder in_progress: { sort_by: :assigned_at }, + pending: { + sort_by: :assigned_at + }, completed: { sort_by: :closed_at } @@ -108,7 +127,6 @@ def initialize(query_type: :in_progress, parent: business_line, query_params: {} @query_type = query_type @parent = parent @query_params = query_params.dup - # Initialize default sorting @query_params[:sort_by] ||= DEFAULT_ORDERING_HASH[query_type][:sort_by] @query_params[:sort_order] ||= "desc" @@ -136,15 +154,21 @@ def issue_type_count appeals_query = Task.send(parent.tasks_query_type[query_type]) .select(shared_select_statement) .joins(ama_appeal: :request_issues) + .joins(issue_modification_request_join) .where(query_constraints) + .where(issue_modification_request_filter) hlr_query = Task.send(parent.tasks_query_type[query_type]) .select(shared_select_statement) .joins(supplemental_claim: :request_issues) + .joins(issue_modification_request_join) .where(query_constraints) + .where(issue_modification_request_filter) sc_query = Task.send(parent.tasks_query_type[query_type]) .select(shared_select_statement) .joins(higher_level_review: :request_issues) + .joins(issue_modification_request_join) .where(query_constraints) + .where(issue_modification_request_filter) nonrating_issue_count = ActiveRecord::Base.connection.execute <<-SQL WITH task_review_issues AS ( @@ -446,6 +470,7 @@ def union_select_statements [ Task.arel_table[Arel.star], issue_count, + pending_issue_count, claimant_name_alias, participant_id_alias, veteran_ssn_alias, @@ -457,7 +482,14 @@ def union_select_statements def issue_count # Issue count alias for sorting and serialization - "COUNT(request_issues.id) AS issue_count" + # This needs a distinct count because the query returns 1 row for each request issue and + # now it can return 1 additional row for each issue modification request with a duplicated request issue.id + "COUNT(DISTINCT request_issues.id) AS issue_count" + end + + def pending_issue_count + # Issue modification request count alias for sorting and serialization + "COUNT(DISTINCT issue_modification_requests.id) AS pending_issue_count" end # Alias for the issue_categories on request issues for sorting and serialization @@ -540,6 +572,24 @@ def bgs_attorneys_join "LEFT JOIN bgs_attorneys ON claimants.participant_id = bgs_attorneys.participant_id" end + def issue_modification_request_join + "LEFT JOIN issue_modification_requests on issue_modification_requests.decision_review_id = tasks.appeal_id + AND issue_modification_requests.decision_review_type = tasks.appeal_type" + end + + def issue_modification_request_filter + if query_type == :pending + "issue_modification_requests.id IS NOT NULL + AND issue_modification_requests.status = 'assigned'" + else + "NOT EXISTS( + SELECT decision_review_id FROM issue_modification_requests WHERE + issue_modification_requests.status = 'assigned' + AND issue_modification_requests.decision_review_id = tasks.appeal_id + AND tasks.appeal_type = issue_modification_requests.decision_review_type)" + end + end + def union_query_join_clauses [ veterans_join, @@ -547,7 +597,8 @@ def union_query_join_clauses people_join, unrecognized_appellants_join, party_details_join, - bgs_attorneys_join + bgs_attorneys_join, + issue_modification_request_join ] end @@ -624,6 +675,7 @@ def decision_reviews_on_request_issues(join_constraint, where_constraints = quer .where(where_constraints) .where(search_all_clause, *search_values) .where(issue_type_filter_predicate(query_params[:filters])) + .where(issue_modification_request_filter) .group(group_by_columns) .arel end @@ -654,6 +706,11 @@ def query_constraints "request_issues.closed_at": nil, "request_issues.ineligible_reason": nil }, + pending: { + assigned_to: parent, + "request_issues.closed_at": nil, + "request_issues.ineligible_reason": nil + }, completed: { assigned_to: parent } diff --git a/app/models/organizations/vha_business_line.rb b/app/models/organizations/vha_business_line.rb index a639ce7edeb..f7d0062b0ed 100644 --- a/app/models/organizations/vha_business_line.rb +++ b/app/models/organizations/vha_business_line.rb @@ -6,14 +6,15 @@ def self.singleton end def included_tabs - [:incomplete, :in_progress, :completed] + [:incomplete, :pending, :in_progress, :completed] end def tasks_query_type { incomplete: "on_hold", in_progress: "active", - completed: "recently_completed" + completed: "recently_completed", + pending: "active" } end diff --git a/app/models/request_issue.rb b/app/models/request_issue.rb index d9d4bd5ca08..286def0744a 100644 --- a/app/models/request_issue.rb +++ b/app/models/request_issue.rb @@ -34,6 +34,7 @@ class RequestIssue < CaseflowRecord has_many :hearing_issue_notes has_one :legacy_issue_optin has_many :legacy_issues + has_many :issue_modification_requests, dependent: :destroy belongs_to :correction_request_issue, class_name: "RequestIssue", foreign_key: "corrected_by_request_issue_id" belongs_to :ineligible_due_to, class_name: "RequestIssue", foreign_key: "ineligible_due_to_id" belongs_to :contested_decision_issue, class_name: "DecisionIssue" diff --git a/app/models/request_issues_update.rb b/app/models/request_issues_update.rb index 5b184d11e49..622c347298e 100644 --- a/app/models/request_issues_update.rb +++ b/app/models/request_issues_update.rb @@ -143,6 +143,10 @@ def handle_sct_issue_updates end end + def can_be_performed? + validate_before_perform + end + private def changes? @@ -154,7 +158,16 @@ def calculate_after_issues before_issues @request_issues_data.map do |issue_data| - review.find_or_build_request_issue_from_intake_data(issue_data) + request_issue = review.find_or_build_request_issue_from_intake_data(issue_data) + + # If the data has a issue modification request id here, then add it in as an association + issue_modification_request_id = issue_data[:issue_modification_request_id] + if issue_modification_request_id && request_issue + issue_modification_request = IssueModificationRequest.find(issue_modification_request_id) + request_issue.issue_modification_requests << issue_modification_request + end + + request_issue end end diff --git a/app/models/serializers/work_queue/decision_review_task_serializer.rb b/app/models/serializers/work_queue/decision_review_task_serializer.rb index 3d7940f3ce7..b7485275733 100644 --- a/app/models/serializers/work_queue/decision_review_task_serializer.rb +++ b/app/models/serializers/work_queue/decision_review_task_serializer.rb @@ -47,11 +47,11 @@ def self.veteran(object) end def self.representative_tz(object) - decision_review(object)&.representative_tz + object[:claimant_name] || decision_review(object)&.representative_tz end attribute :has_poa do |object| - decision_review(object).claimant&.power_of_attorney.present? + object[:claimant_name] || decision_review(object).claimant&.power_of_attorney.present? end attribute :claimant do |object| @@ -79,7 +79,7 @@ def self.representative_tz(object) end attribute :power_of_attorney do |object| - if power_of_attorney(object).nil? + if object[:claimant_name] || power_of_attorney(object).nil? nil else { @@ -105,6 +105,11 @@ def self.representative_tz(object) object[:issue_types] || request_issues(object).active.pluck(:nonrating_issue_category).join(",") end + attribute :pending_issue_modification_count do |object| + object[:pending_issue_count] || + decision_review(object).pending_issue_modification_requests.size + end + attribute :tasks_url do |object| object.assigned_to.tasks_url end diff --git a/app/models/user.rb b/app/models/user.rb index 8e71a163290..4e4650f18c6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -160,6 +160,14 @@ def can_edit_intake_issues? BvaIntake.singleton.admins.include?(self) || member_of_organization?(ClerkOfTheBoard.singleton) end + def vha_business_line_admin_user? + VhaBusinessLine.singleton.admins.include?(self) + end + + def can_request_for_issue_updates? + VhaBusinessLine.singleton.non_admins.include?(self) + end + def can_view_overtime_status? (attorney_in_vacols? || judge_in_vacols?) && FeatureToggle.enabled?(:overtime_revamp, user: self) end diff --git a/app/queries/appeals_non_priority_ready_for_distribution.rb b/app/queries/appeals_non_priority_ready_for_distribution.rb new file mode 100644 index 00000000000..24808e25c0e --- /dev/null +++ b/app/queries/appeals_non_priority_ready_for_distribution.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +class AppealsNonPriorityReadyForDistribution < AppealsReadyForDistribution + # define CSV headers and use this to pull fields to maintain order for Non Priority + NON_PRIORITY_HEADERS = { + docket_number: "Docket Number", + docket: "Docket", + aod: "AOD", + cavc: "CAVC", + receipt_date: "Receipt Date", + assigned_at: "Assigned at", + target_distro_date: "Target Distro Date", + days_before_goal_date: "Days Before Goal Date", + hearing_judge: "Hearing Judge", + veteran_file_number: "Veteran File number", + veteran_name: "Veteran", + affinity_start_date: "Affinity Start Date" + }.freeze + + def self.generate_rows(record) + NON_PRIORITY_HEADERS.keys.map { |key| record[key] } + end + + def self.process + # Convert results to CSV format + + CSV.generate(headers: true) do |csv| + # Add headers to CSV + csv << NON_PRIORITY_HEADERS.values + + # Iterate through results and add each row to CSV + ready_appeals.each do |record| + csv << generate_rows(record) + end + end + end + + def self.ready_appeals + docket_coordinator = DocketCoordinator.new + + docket_coordinator.dockets + .flat_map do |sym, docket| + if sym == :legacy + [] # TODO: Add this back + # appeals = docket.ready_to_distribute_appeals.select { |appeal| appeal["aod"] == 0 } + # legacy_rows(appeals, docket, sym) + else + appeals = docket.ready_priority_nonpriority_appeals(priority: false, ready: true) + ama_rows(appeals, docket, sym) + end + end + end + + # def self.legacy_rows(appeals, docket, sym) + # appeals.map do |appeal| + # veteran_name = FullName.new(appeal["snamef"], nil, appeal["snamel"]).to_s + # vlj_name = FullName.new(appeal["vlj_namef"], nil, appeal["vlj_namel"]).to_s + # hearing_judge = vlj_name.empty? ? nil : vlj_name + # { + # docket_number: appeal["tinum"], + # docket: sym.to_s, + # aod: appeal["aod"] == 1, + # cavc: appeal["cavc"] == 1, + # receipt_date: appeal["bfd19"], + # ready_for_distribution_at: appeal["bfdloout"], + # target_distro_date: target_distro_date(appeal["bfd19"], docket), + # days_before_goal_date: days_before_goal_date(appeal["bfd19"], docket), + # hearing_judge: hearing_judge, + # veteran_file_number: appeal["ssn"] || appeal["bfcorlid"], + # veteran_name: veteran_name + # } + # end + # end + + def self.ama_rows(appeals, docket, sym) + appeals.map do |appeal| + # This comes from the DistributionTask's assigned_at date + ready_for_distribution_at = distribution_task_query(appeal) + # only look for hearings that were held + hearing_judge = with_held_hearings(appeal) + { + docket_number: appeal.docket_number, + docket: sym.to_s, + aod: appeal.aod, + cavc: appeal.cavc, + receipt_date: appeal.receipt_date, + assigned_at: ready_for_distribution_at, + target_distro_date: target_distro_date(appeal.receipt_date, docket), + days_before_goal_date: days_before_goal_date(appeal.receipt_date, docket), + hearing_judge: hearing_judge, + veteran_file_number: appeal.veteran_file_number, + veteran_name: appeal.veteran&.name.to_s, + affinity_start_date: "NA" + } + end + end +end diff --git a/app/queries/appeals_ready_for_distribution.rb b/app/queries/appeals_ready_for_distribution.rb index 703153f8310..5f6ce4c7a99 100644 --- a/app/queries/appeals_ready_for_distribution.rb +++ b/app/queries/appeals_ready_for_distribution.rb @@ -9,6 +9,8 @@ class AppealsReadyForDistribution cavc: "CAVC", receipt_date: "Receipt Date", ready_for_distribution_at: "Ready for Distribution at", + target_distro_date: "Target Distro Date", + days_before_goal_date: "Days Before Goal Date", hearing_judge: "Hearing Judge", veteran_file_number: "Veteran File number", veteran_name: "Veteran", @@ -42,14 +44,14 @@ def self.ready_appeals .flat_map do |sym, docket| appeals = docket.ready_to_distribute_appeals if sym == :legacy - legacy_rows(appeals, sym) + legacy_rows(appeals, docket, sym) else - ama_rows(appeals, sym) + ama_rows(appeals, docket, sym) end end end - def self.legacy_rows(appeals, docket) + def self.legacy_rows(appeals, docket, sym) appeals.map do |appeal| veteran_name = FullName.new(appeal["snamef"], nil, appeal["snamel"]).to_s vlj_name = FullName.new(appeal["vlj_namef"], nil, appeal["vlj_namel"]).to_s @@ -58,11 +60,13 @@ def self.legacy_rows(appeals, docket) { docket_number: appeal["tinum"], - docket: docket.to_s, + docket: sym.to_s, aod: appeal["aod"] == 1, cavc: appeal["cavc"] == 1, receipt_date: appeal["bfd19"], ready_for_distribution_at: appeal["bfdloout"], + target_distro_date: target_distro_date(appeal["bfd19"], docket), + days_before_goal_date: days_before_goal_date(appeal["bfd19"], docket), hearing_judge: hearing_judge, veteran_file_number: appeal["ssn"] || appeal["bfcorlid"], veteran_name: veteran_name, @@ -71,25 +75,21 @@ def self.legacy_rows(appeals, docket) end end - def self.ama_rows(appeals, docket) + def self.ama_rows(appeals, docket, sym) appeals.map do |appeal| # This comes from the DistributionTask's assigned_at date - ready_for_distribution_at = appeal.tasks - .filter { |task| task.class == DistributionTask && task.status == Constants.TASK_STATUSES.assigned } - .first&.assigned_at - + ready_for_distribution_at = distribution_task_query(appeal) # only look for hearings that were held - hearing_judge = appeal.hearings - .filter { |hearing| hearing.disposition = Constants.HEARING_DISPOSITION_TYPES.held } - .first&.judge&.full_name - + hearing_judge = with_held_hearings(appeal) { docket_number: appeal.docket_number, - docket: docket.to_s, + docket: sym.to_s, aod: appeal.aod, cavc: appeal.cavc, receipt_date: appeal.receipt_date, ready_for_distribution_at: ready_for_distribution_at, + target_distro_date: target_distro_date(appeal.receipt_date, docket), + days_before_goal_date: days_before_goal_date(appeal.receipt_date, docket), hearing_judge: hearing_judge, veteran_file_number: appeal.veteran_file_number, veteran_name: appeal.veteran&.name.to_s, @@ -97,4 +97,34 @@ def self.ama_rows(appeals, docket) } end end + + def self.distribution_task_query(appeal) + appeal.tasks + .filter { |task| task.class == DistributionTask && task.status == Constants.TASK_STATUSES.assigned } + .first&.assigned_at + end + + def self.with_held_hearings(appeal) + appeal.hearings + .filter { |hearing| hearing.disposition = Constants.HEARING_DISPOSITION_TYPES.held } + .first&.judge&.full_name + end + + def self.target_distro_date(receipt_date, docket) + if receipt_date.is_a?(String) + receipt_date = Time.zone.parse(receipt_date).to_date + elsif receipt_date.is_a?(Date) || receipt_date.is_a?(DateTime) || receipt_date.is_a?(Time) + receipt_date = receipt_date.to_date + else + return nil + end + receipt_date + docket.docket_time_goal.to_i.days + end + + def self.days_before_goal_date(receipt_date, docket) + target_date = target_distro_date(receipt_date, docket) + return nil if target_date.nil? + + target_date - docket.start_distribution_prior_to_goal.try(:value).to_i.days + end end diff --git a/app/queries/appeals_updated_since_query.rb b/app/queries/appeals_updated_since_query.rb index afe3819b5b3..66dc9f410d5 100644 --- a/app/queries/appeals_updated_since_query.rb +++ b/app/queries/appeals_updated_since_query.rb @@ -28,6 +28,7 @@ def call request_decision_issues request_issues_updates vbms_uploaded_documents + issue_modification_requests ].freeze attr_reader :since_date diff --git a/app/serializers/intake/decision_review_serializer.rb b/app/serializers/intake/decision_review_serializer.rb index 60cfa2161ba..eb457cc8e79 100644 --- a/app/serializers/intake/decision_review_serializer.rb +++ b/app/serializers/intake/decision_review_serializer.rb @@ -18,6 +18,7 @@ class Intake::DecisionReviewSerializer attribute :processed_at, &:establishment_processed_at attribute :veteran_invalid_fields attribute :request_issues, &:request_issues_ui_hash + attribute :task_in_progress, &:task_in_progress? attribute :decision_issues do |object| object.decision_issues.map(&:serialize) @@ -27,6 +28,10 @@ class Intake::DecisionReviewSerializer object.active_nonrating_request_issues.map(&:serialize) end + attribute :pending_issue_modification_requests do |object| + object.pending_issue_modification_requests.map(&:serialize) + end + attribute :contestable_issues_by_date do |object| object.contestable_issues.map(&:serialize) end diff --git a/app/serializers/intake/issue_modification_request_serializer.rb b/app/serializers/intake/issue_modification_request_serializer.rb new file mode 100644 index 00000000000..958f63edf31 --- /dev/null +++ b/app/serializers/intake/issue_modification_request_serializer.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class Intake::IssueModificationRequestSerializer + include FastJsonapi::ObjectSerializer + + attribute :id + attribute :status + attribute :request_type + attribute :remove_original_issue + attribute :nonrating_issue_category + attribute :nonrating_issue_description + attribute :benefit_type + attribute :decision_date + attribute :decided_at + attribute :decision_reason + attribute :request_reason + attribute :request_issue_id + attribute :request_issue + attribute :requestor + attribute :decider + attribute :withdrawal_date +end diff --git a/app/services/issue_modification_requests/updater.rb b/app/services/issue_modification_requests/updater.rb new file mode 100644 index 00000000000..20110e7bec0 --- /dev/null +++ b/app/services/issue_modification_requests/updater.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +# has issue modification request business logic. + +class IssueModificationRequests::Updater + attr_accessor :user, + :review, + :issue_modifications_data + + def initialize(user:, review:, issue_modifications_data:) + @user = user + @review = review + @issue_modifications_data = issue_modifications_data + end + + def non_admin_process! + return false if !non_admin_actions? + + new_modifications_process!(issue_modifications_data[:new]) + edited_modifications_process!(issue_modifications_data[:edited]) + cancelled_modifications_process!(issue_modifications_data[:cancelled]) + end + + def admin_process! + return unless admin_actions? + + process_admin_decisions(issue_modifications_data[:decided]) + end + + def non_admin_actions? + issue_modifications_data.present? && ( + issue_modifications_data[:cancelled].any? || + issue_modifications_data[:edited].any? || + issue_modifications_data[:new].any? + ) + end + + def admin_actions? + issue_modifications_data.present? && issue_modifications_data[:decided].any? + end + + def admin_approvals? + issue_modifications_data.present? && + issue_modifications_data[:decided].any? && + issue_modifications_data[:decided].any? { |issue_mod_data| issue_mod_data[:status].to_sym == :approved } + end + + private + + def new_modifications_process!(new_issues) + new_issues.each do |new_issue| + IssueModificationRequest.create_from_params!(new_issue, review, user) + end + true + end + + def edited_modifications_process!(edited_issues) + edited_issues.each do |edited_issue_data| + issue_modification_request = IssueModificationRequest.find(edited_issue_data[:id]) + + issue_modification_request.edit_from_params!(edited_issue_data, user) + end + + true + end + + def cancelled_modifications_process!(cancelled_issues) + cancelled_issues.each do |cancelled_issue| + issue_modification_request = IssueModificationRequest.find(cancelled_issue[:id]) + + issue_modification_request.cancel_from_params!(user) + end + true + end + + def process_admin_decisions(decided_issue_modification_requests_data) + decided_issue_modification_requests_data.each do |decided_request_data| + issue_modification_request = IssueModificationRequest.find(decided_request_data[:id]) + update_admin_request(issue_modification_request, decided_request_data) + end + end + + def update_admin_request(issue_modification_request, data) + ActiveRecord::Base.transaction do + case data[:status].to_sym + when :denied + issue_modification_request.deny_request_from_params!(data, user) + when :approved + issue_modification_request.approve_request_from_params!(data, user) + end + end + end +end diff --git a/app/views/appeals/edit.html.erb b/app/views/appeals/edit.html.erb index 1e6c975aea4..917a6cf17c5 100644 --- a/app/views/appeals/edit.html.erb +++ b/app/views/appeals/edit.html.erb @@ -1,9 +1,13 @@ <% content_for :full_page_content do %> <%= react_component("IntakeEdit", props: { userDisplayName: current_user.display_name, + userCssId: current_user.css_id, + userFullName: current_user.full_name, userCanWithdrawIssues: current_user.can_withdraw_issues?, userCanSplitAppeal: current_user.can_split_appeal?(appeal), userCanEditIntakeIssues: current_user.can_edit_intake_issues?, + userCanRequestIssueUpdates: current_user.can_request_for_issue_updates?, + userIsVhaAdmin: current_user.vha_business_line_admin_user?, appeal: appeal, hearings: appeal.hearings, hearingDayDate: appeal.hearing_day_if_schedueled, diff --git a/app/views/higher_level_reviews/edit.html.erb b/app/views/higher_level_reviews/edit.html.erb index c8e45f5e183..f05f84aae0a 100644 --- a/app/views/higher_level_reviews/edit.html.erb +++ b/app/views/higher_level_reviews/edit.html.erb @@ -1,8 +1,12 @@ <% content_for :full_page_content do %> <%= react_component("IntakeEdit", props: { userDisplayName: current_user.display_name, + userCssId: current_user.css_id, + userFullName: current_user.full_name, userCanWithdrawIssues: current_user.can_withdraw_issues?, userCanEditIntakeIssues: current_user.can_edit_intake_issues?, + userCanRequestIssueUpdates: current_user.can_request_for_issue_updates?, + userIsVhaAdmin: current_user.vha_business_line_admin_user?, dropdownUrls: dropdown_urls, applicationUrls: application_urls, feedbackUrl: feedback_url, diff --git a/app/views/supplemental_claims/edit.html.erb b/app/views/supplemental_claims/edit.html.erb index 8293ea763a2..bf8d611f463 100644 --- a/app/views/supplemental_claims/edit.html.erb +++ b/app/views/supplemental_claims/edit.html.erb @@ -1,8 +1,12 @@ <% content_for :full_page_content do %> <%= react_component("IntakeEdit", props: { userDisplayName: current_user.display_name, + userCssId: current_user.css_id, + userFullName: current_user.full_name, userCanWithdrawIssues: current_user.can_withdraw_issues?, userCanEditIntakeIssues: current_user.can_edit_intake_issues?, + userCanRequestIssueUpdates: current_user.can_request_for_issue_updates?, + userIsVhaAdmin: current_user.vha_business_line_admin_user?, dropdownUrls: dropdown_urls, applicationUrls: application_urls, feedbackUrl: feedback_url, diff --git a/app/views/test/seeds.html.erb b/app/views/test/seeds.html.erb new file mode 100644 index 00000000000..825a0d2e618 --- /dev/null +++ b/app/views/test/seeds.html.erb @@ -0,0 +1,8 @@ +<% content_for :full_page_content do %> + <%= react_component("TestSeeds", props: { + userDisplayName: current_user.display_name, + dropdownUrls: dropdown_urls, + applicationUrls: application_urls, + feedbackUrl: feedback_url + }) %> +<% end %> diff --git a/client/COPY.json b/client/COPY.json index 26348a3e57d..5735eec2290 100644 --- a/client/COPY.json +++ b/client/COPY.json @@ -1,3 +1,4 @@ + { "CASE_SEARCH_HOME_PAGE_HEADING": "Veteran Case Search", "CASE_SEARCH_INPUT_PLACEHOLDER": "Enter a file number, SSN, or AMA docket number", @@ -40,6 +41,7 @@ "CASE_LIST_TABLE_TASK_ISSUE_COUNT_COLUMN_TITLE": "Issues", "CASE_LIST_TABLE_TASK_VETERAN_PARTICIPANT_ID_COLUMN_TITLE": "Veteran Participant Id", "CASE_LIST_TABLE_TASK_VETERAN_SSN_COLUMN_TITLE": "Veteran SSN", + "CASE_LIST_TABLE_TASK_PENDING_REQUESTS_COLUMN_TITLE": "Pending Requests", "CASE_LIST_TABLE_COMPLETED_BACK_TO_NAME_COLUMN_TITLE": "Sent to", "CASE_LIST_TABLE_TASKS_COLUMN_TITLE": "Tasks", "CASE_LIST_TABLE_TASK_ASSIGNED_BY_COLUMN_TITLE": "Assigned By", @@ -60,6 +62,10 @@ }, "SSN_INVALID_ERR": "Please enter a valid social security number that follows the format: 123-45-6789 or 123456789", "EIN_INVALID_ERR": "Please enter a valid employer identification number that follows the format: 12-3456789 or 123456789", + "ERROR_CREATING_NEW_REQUEST": "Issue status must be in an assigned state", + "ERROR_MODIFYING_EXISTING_REQUEST": "Must be the same requestor or request must be in assigned state", + "ERROR_OPEN_MODIFICATION_EXISTING_REQUEST": "Cannot exceed more than one issue modification request at a time", + "ERROR_DECIDING_ISSUE_MODIFICATION_REQUEST": "Must be an admin to approve or deny requests", "NULL_FILTER_LABEL": "<>", "OTHER_REVIEWS_TABLE_TITLE": "Higher Level Reviews & Supplemental Claims", "OTHER_REVIEWS_TABLE_EP_CODE_COLUMN_TITLE": "EP Codes", @@ -391,12 +397,10 @@ "MTV_CHECKOUT_RETURN_TO_JUDGE_MODAL_DESCRIPTION": "Use this action to return the Motion to Vacate task to your judge if you believe there is an error in the issues that have been marked for vacatur.\n\nIf your judge is unavailable, this will return to the Litigation Support team queue for reassignment.", "MTV_CHECKOUT_RETURN_TO_JUDGE_SUCCESS_TITLE": "%s's Motion to Vacate has been returned to %s", "MTV_CHECKOUT_RETURN_TO_JUDGE_SUCCESS_DETAILS": "If you made a mistake, please email your judge to resolve the issue.", - "MTV_TASK_INSTRUCTIONS": "**Motion To Vacate:** \n", "MTV_TASK_INSTRUCTIONS_TYPE": "**Type:** ", "MTV_TASK_INSTRUCTIONS_DETAIL": "**Detail:** ", "MTV_TASK_INSTRUCTIONS_HYPERLINK": "**Hyperlink:** ", - "VACATE_AND_DE_NOVO_TASK_LABEL": "Vacate and De Novo", "VACATE_AND_READJUDICATION_TASK_LABEL": "Vacate and Readjudication", "STRAIGHT_VACATE_TASK_LABEL": "Straight Vacate", @@ -642,7 +646,6 @@ "SPECIAL_ISSUES_ISSUES_ON_APPEAL_SECTION": "Issues on Appeal: ", "SPECIAL_ISSUES_DIC_OR_PENSION_SECTION": "Dependency and Indemnity Compensation (DIC) or Pension: ", "SPECIAL_ISSUES_BANNER_TEXT": "Military Sexual Trauma and PACT Act will be identified at the issue level. If you need to add these issues, please add them on the next page by editing the applicable issue(s)", - "SPECIAL_ISSUES_NONE_CHOSEN_TITLE": "Choose at least one.", "SPECIAL_ISSUES_NONE_CHOSEN_DETAIL": "If no special issues apply to this case, please confirm by selecting \"No special issues\"", "ADVANCE_ON_DOCKET_MOTION_PAGE_TITLE": "Update Advanced on Docket (AOD) Status", @@ -900,10 +903,9 @@ "CORRECT_REQUEST_ISSUES_SPLIT_APPEAL": "Split appeal", "CORRECT_REQUEST_ISSUES_REMOVE_VBMS_TITLE": "Remove review?", "CORRECT_REQUEST_ISSUES_REMOVE_VBMS_TEXT": "This will remove the review and cancel all the End Products associated with it.", - "CORRECT_REQUEST_ISSUES_REMOVE_CASEFLOW_TITLE": "Withdraw appeal and cancel all tasks", - "CORRECT_REQUEST_ISSUES_REMOVE_CASEFLOW_TEXT": "Removing the last issue will cancel all tasks, close the case, and remove it from your active queue. You will no longer be able to modify or reopen the case.", - "CORRECT_REQUEST_ISSUES_REMOVE_CASEFLOW_TEXT_CONFIRM": "Are you sure you want to do this?", - "CORRECT_REQUEST_ISSUES_REMOVE_MODAL_BUTTON": "Yes, remove", + "CORRECT_REQUEST_ISSUES_REMOVE_CASEFLOW_TITLE": "Delete appeal and cancel all tasks", + "CORRECT_REQUEST_ISSUES_REMOVE_CASEFLOW_TEXT": "Removing the last issue will cancel all tasks, delete the case, and remove it from your active queue. You will no longer be able to modify, search for or reopen the case.", + "CORRECT_REQUEST_ISSUES_REMOVE_MODAL_BUTTON": "Remove", "CORRECT_REQUEST_ISSUES_ORIGINAL_NUMBER": "The review originally had %s %s but now has %s.", "CORRECT_REQUEST_ISSUES_CHANGED_MODAL_TITLE": "Number of issues has changed", "CORRECT_REQUEST_ISSUES_CHANGED_MODAL_TEXT": "Please check that this is the correct number.", @@ -976,12 +978,11 @@ "UNTIMELY_EXEMPTION_COPY_VHA": " OR is this issue related to a VHA Caregiver appeal", "VHA_PRE_DOCKET_ADD_ISSUES_NOTICE": "You have added VHA issues. Once you click \"Submit Appeal\", this appeal will be marked for pre-docketing.", "VHA_PRE_DOCKET_ISSUE_BANNER": "Based on the issue selected, this will go to pre-docket queue.", - + "VHA_ADMIN_DECISION_DATE_REQUIRED_BANNER": "Issues without decision dates cannot be added to this decision review. Please intake a new decision review for any issues without an identified prior decision date.", "MST_SHORT_LABEL": "MST", "PACT_SHORT_LABEL": "PACT", "MST_LABEL": "Military Sexual Trauma (MST)", "PACT_LABEL": "PACT Act", - "VHA_CAMO_PRE_DOCKET_INTAKE_SUCCESS_TITLE": "Appeal recorded and sent to VHA CAMO for document assessment", "VHA_CAREGIVER_SUPPORT_PRE_DOCKET_INTAKE_SUCCESS_TITLE": "Appeal recorded and sent to VHA Caregiver for document assessment", "VHA_NO_DECISION_DATE_BANNER": "This claim will be saved, but cannot be worked on until a decision date is added to this issue.", @@ -1232,6 +1233,10 @@ "VHA_CAMO_ASSIGN_TO_REGIONAL_OFFICE_DROPDOWN_LABEL_VISN": "VISN", "VHA_CAREGIVER_LABEL": "CSP", "VHA_INCOMPLETE_TAB_DESCRIPTION": "Cases that have been only saved and not yet established. Select the claimant name if you need to edit issues.", + "VHA_PENDING_REQUESTS_TAB_ADMIN_DESCRIPTION": "Cases below have requests for issue modification and require action. Please review each case and take the appropriate action for each. Once the issue modification is complete, each case will return to the appropriate queue tab for work by the VHA team.", + "VHA_PENDING_REQUESTS_TAB_DESCRIPTION": "Cases below have requests for issue modification and are waiting Admin review. Once the Admin has taken action on the requested changes, the cases will be returned to the proper queue tab for work by the VHA team. Select the Claimant name if you need to edit a modification request.", + "PENDING_ISSUE_MODIFICATION_REQUESTS_BANNER_TITLE": "This case has pending issue modification requests", + "PENDING_ISSUE_MODIFICATION_REQUESTS_BANNER_MESSAGE": "Requests for issue modifications have been submitted for this case. Dispositions cannot be made until a VHA Admin completes review of the requested changes.", "EDUCATION_LABEL": "Education Service", "PRE_DOCKET_TASK_LABEL": "Pre-Docket", "DOCKET_APPEAL_MODAL_TITLE": "Docket appeal", @@ -1413,6 +1418,8 @@ "DATE_SELECTOR_INVALID_DATE_ERROR": "Please select a valid date", "VHA_ACTION_PLACE_CUSTOM_HOLD_COPY": "Enter a custom number of days for the hold (Value must be between 1 and 45 for VHA users)", "VHA_CANCEL_TASK_INSTRUCTIONS_LABEL": "Why are you returning? Provide any important context", + "DISPOSITION_DECISION_HEADER_ADMIN": "Review each issue and assign the appropriate dispositions.", + "DISPOSITION_DECISION_HEADER_NONADMIN": "Only VHA admins can make edits to Higher-Level Reviews and Supplemental Claims. If you would like to add, remove, or modify an issue within this claim, please request a modification via the button above.", "DISPOSITION_DECISION_DATE_LABEL": "Thank you for completing your decision in Caseflow. Please indicate the decision date.", "PROVIDE_INSTRUCTIONS_AND_CONTEXT_LABEL": "Provide instructions and context for this action", "VHA_ADD_DECISION_DATE_TO_ISSUE_SUCCESS_MESSAGE": "You have successfully updated an issue's decision date", @@ -1445,10 +1452,10 @@ "CASE_DISTRIBUTION_HISTORY_DESCRIPTION": "Change history for Case Distribution Admin shows changes made in the last 365 days.", "CASE_DISTRIBUTION_FOOTER_ASTERISK_DESCRIPTION": "* Denotes a variable that is also relevant to the currently inactive distribution algorithm", "CASE_DISTRIBUTION_DOCKET_TIME_GOALS_SECTION_TITLE": "AMA Non-priority Distribution Goals by Docket", - "CASE_DISTRIBUTION_DOCKET_TIME_GOALS_TITLE_LEFT" : "Docket Time Goal", + "CASE_DISTRIBUTION_DOCKET_TIME_GOALS_TITLE_LEFT": "Docket Time Goal", "CASE_DISTRIBUTION_DOCKET_TIME_DESCRIPTION_LEFT": " set the completion target for AMA non-priority appeals by docket type. It represents the number of calendar days that are added to the receipt date of the appeal to establish the decision target date.", - "CASE_DISTRIBUTION_DOCKET_TIME_GOALS_TITLE_RIGHT" : "Start Distribution Prior to Docket Time Goal", - "CASE_DISTRIBUTION_DOCKET_TIME_DESCRIPTION_RIGHT" : " days sets the number of calendar days prior to the Docket Time Goal for that docket type when appeals become eligible for distribution.", + "CASE_DISTRIBUTION_DOCKET_TIME_GOALS_TITLE_RIGHT": "Start Distribution Prior to Docket Time Goal", + "CASE_DISTRIBUTION_DOCKET_TIME_DESCRIPTION_RIGHT": " days sets the number of calendar days prior to the Docket Time Goal for that docket type when appeals become eligible for distribution.", "CASE_DISTRIBUTION_DOCKET_TIME_NOTE": "Please note, if turned on, non-priority appeals of that docket type will not be distributed until eligible, which may disrupt strict docket-date-order distribution across dockets.", "CASE_DISTRIBUTION_MODAL_TITLE": "Confirm Case Distribution Algorithm Changes", "CASE_DISTRIBUTION_MODAL_DESCRIPTION": "Please confirm the following changes to the Case Distribution algorithm below. Once saved, these changes will apply to the next case distribution event.", @@ -1463,7 +1470,8 @@ "CASE_DISTRIBUTION_EXCLUSION_TABLE_AMA_HEARINGS_HEADER": "AMA Hearings Appeals", "CASE_DISTRIBUTION_EXCLUSION_TABLE_AMA_DIRECT_HEADER": "AMA Direct Review Appeals", "CASE_DISTRIBUTION_EXCLUSION_TABLE_AMA_EVIDENCE_HEADER": "AMA Evidence Submission Appeals", - "CASE_DISTRIBUTION_EXCLUSION_TABLE_OFF": "OFF", + "CASE_DISTRIBUTION_EXCLUSION_TABLE_OFF": "Off", + "CASE_DISTRIBUTION_EXCLUSION_TABLE_ON": "On", "CASE_DISTRIBUTION_EXCLUSION_TABLE_NON_PRIORITY": "All Non-priority", "CASE_DISTRIBUTION_EXCLUSION_TABLE_PRIORITY": "All Priority", "CASE_DISTRIBUTION_AFFINITY_DAYS_H2_TITLE": "Affinity Days", @@ -1479,5 +1487,34 @@ "CASE_DISTRIBUTION_LEVER_HISTORY_DATA_ELEMENT": "Data Element Changed", "CASE_DISTRIBUTION_LEVER_HISTORY_PREV_VALUE": "Previous Value", "CASE_DISTRIBUTION_LEVER_HISTORY_UPDATED_VALUE": "Updated Value", - "CASE_DISTRIBUTION_STATIC_LEVERS_VALUES": "Values" + "CASE_DISTRIBUTION_STATIC_LEVERS_VALUES": "Values", + "TEST_SEEDS_ALERT_MESSAGE": " in progress", + "TEST_SEEDS_RUN_SEEDS": "Scenario Seeds", + "TEST_SEEDS_CUSTOM_SEEDS": "Custom Seeds", + "VHA_BANNER_FOR_NEWLY_APPROVED_REQUESTED_ISSUE": "This is a new issue based on a requested issue addition.", + "ISSUE_MODIFICATION_REQUESTS": { + "ADDITION": { + "REQUEST_TYPE": "addition", + "SECTION_TITLE": "Requested Additional Issues", + "DETAILS": "Reason for requested issue addition" + }, + "MODIFICATION": { + "REQUEST_TYPE": "modification", + "SECTION_TITLE": "Requested Changes", + "DETAILS": "Reason for requested modification" + }, + "REMOVAL": { + "REQUEST_TYPE": "removal", + "SECTION_TITLE": "Requested Issue Removal", + "DETAILS": "Reason for requested removal of issue" + }, + "WITHDRAWAL": { + "REQUEST_TYPE": "withdrawal", + "SECTION_TITLE": "Requested Issue Withdrawal", + "DETAILS": "Reason for requested withdrawal of issue", + "DATE": "Requested date for withdrawal" + } + }, + "VHA_BANNER_DISPOSITIONS_CANNOT_BE_UPDATED_NON_ADMIN": "Requests for issue modifications have been submitted for this case. Dispositions cannot be made until a VHA admin completes review of the requested changes.", + "VHA_BANNER_DISPOSITIONS_CANNOT_BE_UPDATED_ADMIN": "Requests for issue modifications have been submitted for this case. Dispositions cannot be made until a VHA admin completes review of the requested changes. Click the \"Edit issues\" button above to review the issue modification requests." } diff --git a/client/app/caseDistribution/components/DocketTimeGoals.jsx b/client/app/caseDistribution/components/DocketTimeGoals.jsx index 520a25732c1..3afb073a77f 100644 --- a/client/app/caseDistribution/components/DocketTimeGoals.jsx +++ b/client/app/caseDistribution/components/DocketTimeGoals.jsx @@ -149,10 +149,12 @@ const DocketTimeGoals = () => { id={`${distributionPriorLever.item}-lever-toggle`} >
- - {distributionPriorLever.is_toggle_active ? 'On' : 'Off'} + {distributionPriorLever.is_toggle_active ? + `On, ${distributionPriorLever.value} ${distributionPriorLever.unit}` : 'Off'}
diff --git a/client/app/caseDistribution/components/ExcludeDocketLever.jsx b/client/app/caseDistribution/components/ExcludeDocketLever.jsx new file mode 100644 index 00000000000..f973495f09b --- /dev/null +++ b/client/app/caseDistribution/components/ExcludeDocketLever.jsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { useDispatch } from 'react-redux'; +import RadioField from 'app/components/RadioField'; +import { updateLeverValue } from '../reducers/levers/leversActions'; + +const ExcludeDocketLever = (levers) => { + const dispatch = useDispatch(); + let selectedLever = levers.lever; + const onChangeSelected = (selected) => (event) => { + dispatch(updateLeverValue(selected.leverGroup, selected.item, event)); + }; + + return ( + + + + ); +}; + +export default ExcludeDocketLever; diff --git a/client/app/caseDistribution/components/ExclusionTable.jsx b/client/app/caseDistribution/components/ExclusionTable.jsx index 6eed5b6a1c7..f10fb43da85 100644 --- a/client/app/caseDistribution/components/ExclusionTable.jsx +++ b/client/app/caseDistribution/components/ExclusionTable.jsx @@ -1,38 +1,126 @@ -import React from 'react'; -import { useSelector } from 'react-redux'; +/* eslint-disable camelcase */ +import React, { useState, useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; import ToggleSwitch from 'app/components/ToggleSwitch/ToggleSwitch'; -import RadioField from 'app/components/RadioField'; import cx from 'classnames'; import COPY from '../../../COPY'; import DISTRIBUTION from '../../../constants/DISTRIBUTION'; import { getUserIsAcdAdmin } from '../reducers/levers/leversSelector'; +import ACD_LEVERS from '../../../constants/ACD_LEVERS'; +import ExcludeDocketLever from './ExcludeDocketLever'; +import { updateLeverValue } from '../reducers/levers/leversActions'; const ExclusionTable = () => { const theState = useSelector((state) => state); + const dispatch = useDispatch(); const isUserAcdAdmin = getUserIsAcdAdmin(theState); - // Placeholder options until future implementation - let options = [ - { displayText: 'On', - value: '1', - disabled: true - }, - { displayText: 'Off', - value: '2', - disabled: true + let docketLevers = theState.caseDistributionLevers?.levers?.docket_levers ?? []; + + docketLevers = docketLevers.sort((leverA, leverB) => leverA.lever_group_order - leverB.lever_group_order); + + const priorityLevers = docketLevers.filter((lever) => lever.control_group === ACD_LEVERS.priority); + const nonPriorityLevers = docketLevers.filter((lever) => lever.control_group === ACD_LEVERS.non_priority); + + const priorityRadios = priorityLevers.map((lever) => ({ + displayText: lever.title, + item: lever.item, + value: lever.value, + disabled: lever.is_disabled_in_ui, + options: lever.options, + leverGroup: lever.lever_group, + })); + + const nonPriorityRadios = nonPriorityLevers.map((lever) => ({ + displayText: lever.title, + item: lever.item, + value: lever.value, + disabled: lever.is_disabled_in_ui, + options: lever.options, + leverGroup: lever.lever_group, + })); + + const [priorityToggle, setPriorityToggle] = useState(false); + const [nonPriorityToggle, setNonPriorityToggle] = useState(false); + const [comboPriorityToggle, setComboPriorityToggle] = useState(false); + const [comboNonPriorityToggle, setComboNonPriorityToggle] = useState(false); + + useEffect(() => { + const allPrioritySelected = priorityRadios.every((lever) => lever.value === 'true'); + const allPriorityUnselected = priorityRadios.every((lever) => lever.value === 'false'); + const allNonPrioritySelected = nonPriorityRadios.every((lever) => lever.value === 'true'); + const allNonPriorityUnselected = nonPriorityRadios.every((lever) => lever.value === 'false'); + + if (allPrioritySelected) { + setPriorityToggle(true); + setComboPriorityToggle(false); + } else if (allPriorityUnselected) { + setPriorityToggle(false); + setComboPriorityToggle(false); + } else { + setPriorityToggle(false); + setComboPriorityToggle(true); + } + + if (allNonPrioritySelected) { + setNonPriorityToggle(true); + setComboNonPriorityToggle(false); + } else if (allNonPriorityUnselected) { + setNonPriorityToggle(false); + setComboNonPriorityToggle(false); + } else { + setNonPriorityToggle(false); + setComboNonPriorityToggle(true); } - ]; + }, [priorityRadios, nonPriorityRadios]); + + const handleToggleChange = (isPriority) => { + if (isPriority) { + const toggleState = priorityToggle !== true; + + setPriorityToggle(toggleState); + const newToggleState = toggleState ? 'true' : 'false'; - const generateUniqueId = (leverItem, optionValue, index) => `${leverItem}-${optionValue}-${index}`; + priorityRadios.forEach((lever) => { + dispatch(updateLeverValue(lever.leverGroup, lever.item, newToggleState)); + }); + } else { + const toggleState = nonPriorityToggle !== true; + + setNonPriorityToggle(toggleState); + const newToggleState = toggleState ? 'true' : 'false'; + + nonPriorityRadios.forEach((lever) => { + dispatch(updateLeverValue(lever.leverGroup, lever.item, newToggleState)); + }); + } + }; + + const filterOptionValue = (lever) => { + let enabled = lever?.value; + + if (enabled === 'true') { + return COPY.CASE_DISTRIBUTION_EXCLUSION_TABLE_ON; + } + + return COPY.CASE_DISTRIBUTION_EXCLUSION_TABLE_OFF; + }; + + const buildAriaLabel = (lever, isPriority) => { + let priority = isPriority ? 'Priority' : 'Non Priority'; + let enabled = lever.value ? 'On' : 'Off'; + + return `${priority } ${ lever.title } ${ enabled}`; + }; return (
- + - - - + + {nonPriorityRadios && nonPriorityRadios.map((lever) => ( + + ))} - - - - + {priorityRadios && priorityRadios.map((lever) => ( + + ))} : @@ -196,26 +202,17 @@ const ExclusionTable = () => {

{COPY.CASE_DISTRIBUTION_EXCLUSION_TABLE_NON_PRIORITY}

- - - - + {nonPriorityRadios && nonPriorityRadios.map((lever) => ( + + ))} @@ -223,25 +220,17 @@ const ExclusionTable = () => {

{COPY.CASE_DISTRIBUTION_EXCLUSION_TABLE_PRIORITY}

- - - - + {priorityRadios && priorityRadios.map((lever) => ( + + ))} }
{' '} {COPY.CASE_DISTRIBUTION_EXCLUSION_TABLE_LEGACY_APPEALS_HEADER} @@ -63,63 +151,22 @@ const ExclusionTable = () => { - - - - - - generateUniqueId(DISTRIBUTION.all_non_priority, option.value, index)} - /> - - - - - generateUniqueId(DISTRIBUTION.all_non_priority, option.value, index)} - /> - - - - - generateUniqueId(DISTRIBUTION.all_non_priority, option.value, index)} - /> - - - - - generateUniqueId(DISTRIBUTION.all_non_priority, option.value, index)} + selected = {nonPriorityToggle} + toggleSelected = {() => handleToggleChange(false)} + isIdle = {comboNonPriorityToggle} /> + +
{ - - - - - generateUniqueId(DISTRIBUTION.all_priority, option.value, index)} - /> - - - - - generateUniqueId(DISTRIBUTION.all_priority, option.value, index)} - /> - - - - - generateUniqueId(DISTRIBUTION.all_priority, option.value, index)} - /> - - - - - generateUniqueId(DISTRIBUTION.all_priority, option.value, index)} + selected = {priorityToggle} + toggleSelected = {() => handleToggleChange(true)} + isIdle = {comboPriorityToggle} /> + +
- - - - - - - - + +
- - - - - - - - + +
diff --git a/client/app/caseDistribution/components/LeverHistory.jsx b/client/app/caseDistribution/components/LeverHistory.jsx index 892dedf4c30..279df647f35 100644 --- a/client/app/caseDistribution/components/LeverHistory.jsx +++ b/client/app/caseDistribution/components/LeverHistory.jsx @@ -16,7 +16,7 @@ const LeverHistory = () => { return `${value}`; } - return `${value} ${entry.units[idx]}`; + return `${value} ${entry.units[idx] === 'null' ? '' : entry.units[idx]}`; }; return ( diff --git a/client/app/caseDistribution/constants.js b/client/app/caseDistribution/constants.js index 56579d66055..82989593863 100644 --- a/client/app/caseDistribution/constants.js +++ b/client/app/caseDistribution/constants.js @@ -7,14 +7,14 @@ export const Constant = { }; export const sectionTitles = { - [DISTRIBUTION.ama_hearings_start_distribution_prior_to_goals]: DISTRIBUTION.ama_hearings_section_title, + [DISTRIBUTION.ama_hearing_start_distribution_prior_to_goals]: DISTRIBUTION.ama_hearings_section_title, [DISTRIBUTION.ama_direct_review_start_distribution_prior_to_goals]: DISTRIBUTION.ama_direct_review_section_title, [DISTRIBUTION.ama_evidence_submission_start_distribution_prior_to_goals]: DISTRIBUTION.ama_evidence_submission_section_title }; export const docketTimeGoalPriorMappings = { - [DISTRIBUTION.ama_hearings_start_distribution_prior_to_goals]: - DISTRIBUTION.ama_hearings_docket_time_goals, + [DISTRIBUTION.ama_hearing_start_distribution_prior_to_goals]: + DISTRIBUTION.ama_hearing_docket_time_goals, [DISTRIBUTION.ama_direct_review_start_distribution_prior_to_goals]: DISTRIBUTION.ama_direct_review_docket_time_goals, [DISTRIBUTION.ama_evidence_submission_start_distribution_prior_to_goals]: diff --git a/client/app/caseDistribution/pages/CaseDistributionApp.jsx b/client/app/caseDistribution/pages/CaseDistributionApp.jsx index 11e0fe5223c..3b2af59994d 100644 --- a/client/app/caseDistribution/pages/CaseDistributionApp.jsx +++ b/client/app/caseDistribution/pages/CaseDistributionApp.jsx @@ -33,7 +33,7 @@ class CaseDistributionApp extends React.PureComponent { CaseDistributionApp.propTypes = { acdLeversForStore: PropTypes.object, - loadAcdExcludeFromAffinity: PropTypes.bool, + loadAcdExcludeFromAffinity: PropTypes.func, acd_exclude_from_affinity: PropTypes.bool, acd_history: PropTypes.array, user_is_an_acd_admin: PropTypes.bool, diff --git a/client/app/caseDistribution/test.jsx b/client/app/caseDistribution/test.jsx index 6a3a3765998..68b83c16f55 100644 --- a/client/app/caseDistribution/test.jsx +++ b/client/app/caseDistribution/test.jsx @@ -18,12 +18,14 @@ class CaseDistributionTest extends React.PureComponent { this.state = { isReseedingAod: false, isReseedingNonAod: false, + isReseedingAmaDocketGoals: false, + isReseedingDocketPriority: false }; } reseedAod = () => { this.setState({ isReseedingAod: true }); - ApiUtil.post('/run-demo-aod-seeds').then(() => { + ApiUtil.post('/case_distribution_levers_tests/run_demo_aod_hearing_seeds').then(() => { this.setState({ isReseedingAod: false, }); @@ -37,7 +39,7 @@ class CaseDistributionTest extends React.PureComponent { reseedNonAod = () => { this.setState({ isReseedingNonAod: true }); - ApiUtil.post('/run-demo-non-aod-seeds').then(() => { + ApiUtil.post('/case_distribution_levers_tests/run_demo_non_aod_hearing_seeds').then(() => { this.setState({ isReseedingNonAod: false, }); @@ -49,6 +51,34 @@ class CaseDistributionTest extends React.PureComponent { }); }; + reseedAmaDocketGoals = () => { + this.setState({ isReseedingAmaDocketGoals: true }); + ApiUtil.post('/case_distribution_levers_tests/run-demo-ama-docket-goals').then(() => { + this.setState({ + isReseedingAmaDocketGoals: false, + }); + }, (err) => { + console.warn(err); + this.setState({ + isReseedingAmaDocketGoals: false, + }); + }); + }; + + reseedDocketPriority = () => { + this.setState({ isReseedingDocketPriority: true }); + ApiUtil.post('/case_distribution_levers_tests/run-demo-docket-priority').then(() => { + this.setState({ + isReseedingDocketPriority: false, + }); + }, (err) => { + console.warn(err); + this.setState({ + isReseedingDocketPriority: false, + }); + }); + }; + render() { const Router = this.props.router || BrowserRouter; const appName = 'Case Distribution'; @@ -202,30 +232,34 @@ class CaseDistributionTest extends React.PureComponent {

Distribution Status


Run Seed Files


diff --git a/client/app/components/Modal.jsx b/client/app/components/Modal.jsx index ddd2493b625..05507af79a2 100644 --- a/client/app/components/Modal.jsx +++ b/client/app/components/Modal.jsx @@ -7,14 +7,10 @@ import Button from './Button'; import _ from 'lodash'; import { css } from 'glamor'; -const modalTextStyling = css({ width: '100%', fontFamily: 'Source Sans Pro' }); +const modalTextStyling = css({ width: '100%', fontFamily: 'Source Sans Pro', flexGrow: 1 }); const iconStyling = css({ - float: 'left', - flexGrow: 0, - flexShrink: 0, - flexBasis: '13%', - marginTop: '1rem', + marginRight: '2rem', color: '#323a45', }); @@ -147,12 +143,10 @@ export default class Modal extends React.Component { Close -
+
{icon && } -
-

{title}

-
{children}
-
+

{title}

+
{children}
{noDivider ? '' :
}
{modalButtons}
diff --git a/client/app/components/Modal.stories.js b/client/app/components/Modal.stories.js index b9b9f23fbc1..f210db84910 100644 --- a/client/app/components/Modal.stories.js +++ b/client/app/components/Modal.stories.js @@ -60,3 +60,7 @@ const Template = (args) => { export const Basic = Template.bind({}); +export const Icon = Template.bind({}); +Icon.args = { + icon: 'warning' +}; diff --git a/client/app/components/NumberField.jsx b/client/app/components/NumberField.jsx index 83cb6430032..883d1de0829 100644 --- a/client/app/components/NumberField.jsx +++ b/client/app/components/NumberField.jsx @@ -21,6 +21,7 @@ export default class NumberField extends React.Component { onChange={this.onChange} aria-readonly={this.props.readOnly} ariaLabelText={this.props.ariaLabelText} + useAriaLabel={this.props.useAriaLabel} disabled={this.props.disabled} />
; @@ -46,6 +47,7 @@ NumberField.propTypes = { } }, ariaLabelText: PropTypes.string, + useAriaLabel: PropTypes.bool, placeholder: PropTypes.string, isInteger: PropTypes.bool, readOnly: PropTypes.bool, diff --git a/client/app/components/SearchableDropdown.jsx b/client/app/components/SearchableDropdown.jsx index 2496a46dbff..2b2764036e2 100644 --- a/client/app/components/SearchableDropdown.jsx +++ b/client/app/components/SearchableDropdown.jsx @@ -7,6 +7,7 @@ import _, { isPlainObject, isNull, kebabCase, isEmpty, isString } from 'lodash'; import classNames from 'classnames'; import { css } from 'glamor'; import { FormLabel } from './FormLabel'; +import { DoubleArrowIcon } from 'app/components/icons/DoubleArrowIcon'; const TAG_ALREADY_EXISTS_MSG = 'Tag already exists'; const NO_RESULTS_TEXT = 'Not an option'; @@ -52,6 +53,14 @@ const CustomInput = (props) => { return ; }; +const DoubleArrowDropdownIndicator = (props) => { + return ( + + + + ); +}; + export class SearchableDropdown extends React.Component { constructor(props) { super(props); @@ -162,6 +171,7 @@ export class SearchableDropdown extends React.Component { options, defaultOptions, defaultValue, + doubleArrow, filterOption, isClearable, inputRef, @@ -240,6 +250,14 @@ export class SearchableDropdown extends React.Component { const handleNoOptions = () => noResultsText ?? (creatable ? null : NO_RESULTS_TEXT); + const replacedComponents = { + Input: CustomInput, + MenuList: CustomMenuList, + Option: CustomOption, + ...(doubleArrow && { DropdownIndicator: DoubleArrowDropdownIndicator }), + ...(doubleArrow && { IndicatorSeparator: null }) + }; + return (
@@ -251,7 +269,7 @@ export class SearchableDropdown extends React.Component { )}
{ const buttonStyles = cx('toggleButton', { @@ -17,6 +18,7 @@ const ToggleSwitch = ({ const h5Style = cx('toggleButtonText', { switchDisabled: disabled, + switchIdle: isIdle, switchOn: selected, switchOff: !selected }); @@ -49,7 +51,8 @@ ToggleSwitch.propTypes = { id: PropTypes.string, name: PropTypes.string, optionLabels: PropTypes.array, - disabled: PropTypes.bool + disabled: PropTypes.bool, + isIdle: PropTypes.bool }; export default ToggleSwitch; diff --git a/client/app/index.js b/client/app/index.js index 3849db6d60e..2b7de044bc9 100644 --- a/client/app/index.js +++ b/client/app/index.js @@ -59,6 +59,7 @@ import MPISearch from 'app/mpi/MPISearch'; import Admin from 'app/admin'; import CaseDistribution from 'app/caseDistribution'; import CaseDistributionTest from 'app/caseDistribution/test'; +import TestSeeds from 'app/testSeeds'; import uuid from 'uuid'; const COMPONENTS = { @@ -95,7 +96,8 @@ const COMPONENTS = { MPISearch, Admin, CaseDistribution, - CaseDistributionTest + CaseDistributionTest, + TestSeeds }; const componentWrapper = (component) => (props, railsContext, domNodeId) => { @@ -180,7 +182,8 @@ const componentWrapper = (component) => (props, railsContext, domNodeId) => { './explain/index', './mpi/MPISearch', './admin/index', - './caseDistribution/index' + './caseDistribution/index', + './testSeeds/index' ], () => renderApp(component) ); diff --git a/client/app/intake/IntakeFrame.jsx b/client/app/intake/IntakeFrame.jsx index 56b57338bfb..7cff6e48322 100644 --- a/client/app/intake/IntakeFrame.jsx +++ b/client/app/intake/IntakeFrame.jsx @@ -120,6 +120,7 @@ export const IntakeFrame = (props) => { diff --git a/client/app/intake/actions/issueModificationRequest.js b/client/app/intake/actions/issueModificationRequest.js new file mode 100644 index 00000000000..a785800dce2 --- /dev/null +++ b/client/app/intake/actions/issueModificationRequest.js @@ -0,0 +1,91 @@ +import { ACTIONS } from '../constants'; + +export const toggleRequestIssueModificationModal = (index) => ({ + type: ACTIONS.TOGGLE_REQUEST_ISSUE_MODIFICATION_MODAL, + payload: { index } +}); + +export const toggleRequestIssueRemovalModal = (index) => ({ + type: ACTIONS.TOGGLE_REQUEST_ISSUE_REMOVAL_MODAL, + payload: { index } +}); + +export const toggleRequestIssueWithdrawalModal = (index) => ({ + type: ACTIONS.TOGGLE_REQUEST_ISSUE_WITHDRAWAL_MODAL, + payload: { index } +}); + +export const toggleRequestIssueAdditionModal = () => ({ + type: ACTIONS.TOGGLE_REQUEST_ISSUE_ADDITION_MODAL +}); + +export const toggleCancelPendingRequestIssueModal = () => ({ + type: ACTIONS.TOGGLE_CANCEL_PENDING_REQUEST_ISSUE_MODAL +}); + +export const toggleConfirmPendingRequestIssueModal = (data) => ({ + type: ACTIONS.TOGGLE_CONFIRM_PENDING_REQUEST_ISSUE_MODAL, + payload: { data } +}); + +export const updatePendingReview = (identifier, data) => ( + { + type: ACTIONS.UPDATE_PENDING_REVIEW, + payload: { identifier, data } + } +); + +export const moveToPendingReviewSection = (issueModificationRequest) => ( + { + type: ACTIONS.MOVE_TO_PENDING_REVIEW, + payload: { issueModificationRequest } + }); + +export const addToPendingReviewSection = (issueModificationRequest) => ( + { + type: ACTIONS.ADD_TO_PENDING_REVIEW, + payload: { issueModificationRequest } + } +); + +export const removeFromPendingReviewSection = (index) => ( + { + type: ACTIONS.REMOVE_FROM_PENDING_REVIEW, + payload: { index } + } +); + +export const issueWithdrawalRequestApproved = (identifier, issueModificationRequest) => ( + { + type: ACTIONS.ISSUE_WITHDRAW_REQUEST_APPROVED, + payload: { identifier, issueModificationRequest } + } +); + +export const cancelOrRemovePendingReview = (issueModificationRequest) => ( + { + type: ACTIONS.CANCEL_OR_REMOVE_PENDING_REVIEW, + payload: { issueModificationRequest } + } +); + +export const issueAdditionRequestApproved = (issueModificationRequest) => ( + { + type: ACTIONS.ISSUE_ADDITION_REQUEST_APPROVED, + payload: { issueModificationRequest } + } +); + +export const updateActiveIssueModificationRequest = (data) => ( + { + type: ACTIONS.ACTIVE_ISSUE_MODIFICATION_REQUEST, + payload: { data } + } +); + +export const setAllApprovedIssueModificationsWithdrawalDates = (withdrawalDate) => ( + { + type: ACTIONS.SET_ALL_APPROVED_ISSUE_MODIFICATION_WITHDRAWAL_DATES, + payload: { withdrawalDate } + } +); diff --git a/client/app/intake/components/AddDecisionDateModal/__snapshots__/AddDecisionDateModal.test.js.snap b/client/app/intake/components/AddDecisionDateModal/__snapshots__/AddDecisionDateModal.test.js.snap index 59921b57669..490fddeee8c 100644 --- a/client/app/intake/components/AddDecisionDateModal/__snapshots__/AddDecisionDateModal.test.js.snap +++ b/client/app/intake/components/AddDecisionDateModal/__snapshots__/AddDecisionDateModal.test.js.snap @@ -47,69 +47,66 @@ Object {
+

+ Add Decision Date +

-

- Add Decision Date -

+
+ + Issue: + + Beneficiary Travel +
+
+ + Benefit type: + + Veterans Health Administration +
+
+ + Issue description: + + Beneficiary Travel - Issue Description +
-
- - Issue: - - Beneficiary Travel -
-
- - Benefit type: - - Veterans Health Administration -
-
- - Issue description: - - Beneficiary Travel - Issue Description -
+
- -
- -
+
@@ -189,69 +186,66 @@ Object {
+

+ Add Decision Date +

-

- Add Decision Date -

+
+ + Issue: + + Beneficiary Travel +
+
+ + Benefit type: + + Veterans Health Administration +
+
+ + Issue description: + + Beneficiary Travel - Issue Description +
-
- - Issue: - - Beneficiary Travel -
-
- - Benefit type: - - Veterans Health Administration -
-
- - Issue description: - - Beneficiary Travel - Issue Description -
+
- -
- -
+
diff --git a/client/app/intake/components/AddIssueManager.jsx b/client/app/intake/components/AddIssueManager.jsx index c6e75e159f1..da5f5671e29 100644 --- a/client/app/intake/components/AddIssueManager.jsx +++ b/client/app/intake/components/AddIssueManager.jsx @@ -44,7 +44,7 @@ class AddIssueManager extends React.Component { } setupAddIssuesModal = () => { - const { intakeData, formType, featureToggles, userCanEditIntakeIssues } = this.props; + const { intakeData, formType, featureToggles, userCanEditIntakeIssues, userIsVhaAdmin } = this.props; return { component: AddIssuesModal, @@ -53,6 +53,7 @@ class AddIssueManager extends React.Component { formType, featureToggles, userCanEditIntakeIssues, + userIsVhaAdmin, onCancel: () => this.cancel(), onSubmit: ({ selectedContestableIssueIndex, currentIssue, notes }) => { this.setState( @@ -122,7 +123,7 @@ class AddIssueManager extends React.Component { }; setupNonratingRequestIssueModal = () => { - const { intakeData, formType, featureToggles, userCanEditIntakeIssues } = this.props; + const { intakeData, formType, featureToggles, userCanEditIntakeIssues, userIsVhaAdmin } = this.props; return { component: NonratingRequestIssueModal, @@ -131,6 +132,7 @@ class AddIssueManager extends React.Component { formType, featureToggles, userCanEditIntakeIssues, + userIsVhaAdmin, submitText: this.hasLegacyAppeals() ? 'Next' : 'Add this issue', onCancel: () => this.cancel(), onSkip: () => this.setState({ currentModal: 'UnidentifiedIssuesModal' }), @@ -340,6 +342,7 @@ AddIssueManager.propTypes = { onComplete: PropTypes.func, featureToggles: PropTypes.object, userCanEditIntakeIssues: PropTypes.bool, + userIsVhaAdmin: PropTypes.bool, intakeData: PropTypes.object, formType: PropTypes.string, addIssue: PropTypes.func, diff --git a/client/app/intake/components/AddIssuesModal.jsx b/client/app/intake/components/AddIssuesModal.jsx index 649b1ee4c17..028770dfbe5 100644 --- a/client/app/intake/components/AddIssuesModal.jsx +++ b/client/app/intake/components/AddIssuesModal.jsx @@ -214,6 +214,7 @@ class AddIssuesModal extends React.Component { renderPact={renderTrueOrFalse('pact')} renderJustification={renderTrueOrFalse('justification')} userCanEditIntakeIssues={this.props.userCanEditIntakeIssues} + userIsVhaAdmin={this.props.userIsVhaAdmin} mstChecked={this.state.mstChecked} setMstCheckboxFunction={this.mstCheckboxChange} pactChecked={this.state.pactChecked} @@ -280,6 +281,7 @@ AddIssuesModal.propTypes = { intakeData: PropTypes.object, featureToggles: PropTypes.object, userCanEditIntakeIssues: PropTypes.bool, + userIsVhaAdmin: PropTypes.bool, formType: PropTypes.string }; diff --git a/client/app/intake/components/AddIssuesModal.stories.js b/client/app/intake/components/AddIssuesModal.stories.js index b89da7da348..e6a54479bba 100644 --- a/client/app/intake/components/AddIssuesModal.stories.js +++ b/client/app/intake/components/AddIssuesModal.stories.js @@ -19,7 +19,8 @@ const ReduxDecorator = (Story) => ( { + + const { + pendingIssueModificationRequest, + onCancel, + removeFromPendingReviewSection, + toggleCancelPendingRequestIssueModal + } = props; + + const requestIssue = pendingIssueModificationRequest.requestIssue; + + const withdrawalDate = ( +
+ Request date for withdrawal: {formatDateStr(pendingIssueModificationRequest?.withdrawalDate)} +
+ ); + + const requestReason = ( +
+ {capitalize(pendingIssueModificationRequest.requestType)} request reason: + {pendingIssueModificationRequest.requestReason} +
+ ); + + const baseIssueInformation = ( +
+

Pending issue request

+ Issue type: {pendingIssueModificationRequest.nonratingIssueCategory}
+ Decision date: {formatDateStr(pendingIssueModificationRequest.decisionDate)}
+ Issue description: {pendingIssueModificationRequest.nonratingIssueDescription || + pendingIssueModificationRequest.nonRatingIssueDescription}
+
+ ); + + const originalIssue = ( +
+

Current issue

+ Issue type: {requestIssue?.nonratingIssueCategory || requestIssue?.category}
+ Decision date: {formatDateStr(requestIssue?.decisionDate)}
+ Issue description: {requestIssue?.nonratingIssueDescription || + requestIssue?.nonRatingIssueDescription}
+
+ ); + + const modalInfo = { + [COPY.ISSUE_MODIFICATION_REQUESTS.ADDITION.REQUEST_TYPE]: ( +
+ {baseIssueInformation} + {requestReason} +
+ ), + [COPY.ISSUE_MODIFICATION_REQUESTS.MODIFICATION.REQUEST_TYPE]: ( +
+ {originalIssue} +
+ {baseIssueInformation} + {requestReason} +
+ ), + [COPY.ISSUE_MODIFICATION_REQUESTS.REMOVAL.REQUEST_TYPE]: ( +
+ {baseIssueInformation} + {requestReason} +
+ ), + [COPY.ISSUE_MODIFICATION_REQUESTS.WITHDRAWAL.REQUEST_TYPE]: ( +
+ {baseIssueInformation} + {withdrawalDate} + {requestReason} +
+ ) + }; + + const handleSubmit = () => { + removeFromPendingReviewSection(pendingIssueModificationRequest); + toggleCancelPendingRequestIssueModal(); + }; + + return ( + + {modalInfo[pendingIssueModificationRequest.requestType]} + + ); +}; + +CancelPendingRequestIssueModal.propTypes = { + pendingIssueModificationRequest: PropTypes.object, + onCancel: PropTypes.func, + removeFromPendingReviewSection: PropTypes.func, + toggleCancelPendingRequestIssueModal: PropTypes.func +}; diff --git a/client/app/intake/components/ConfirmPendingRequestIssueModal.jsx b/client/app/intake/components/ConfirmPendingRequestIssueModal.jsx new file mode 100644 index 00000000000..c43cae27e93 --- /dev/null +++ b/client/app/intake/components/ConfirmPendingRequestIssueModal.jsx @@ -0,0 +1,90 @@ +import React from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import Modal from '../../components/Modal'; +import { formatDateStr } from '../../util/DateUtil'; +import COPY from '../../../COPY'; +import { convertPendingIssueToRequestIssue } from '../util/issueModificationRequests'; +import { addIssue, removeIssue } from '../actions/addIssues'; +import { + updatePendingReview, + toggleConfirmPendingRequestIssueModal +} from '../actions/issueModificationRequest'; + +export const ConfirmPendingRequestIssueModal = () => { + const activeIssueModificationRequest = useSelector((state) => state.activeIssueModificationRequest); + + const requestIssue = activeIssueModificationRequest.requestIssue; + + const indexOfOriginalIssue = useSelector( + (state) => state.addedIssues.findIndex((issue) => issue.id === activeIssueModificationRequest.requestIssue.id)); + + const dispatch = useDispatch(); + + const originalIssue = ( +
+

Delete original issue

+ Issue type: {requestIssue?.nonratingIssueCategory || requestIssue?.category}
+ Decision date: {formatDateStr(requestIssue?.decisionDate)}
+ Issue description: {requestIssue?.nonratingIssueDescription || + requestIssue?.nonRatingIssueDescription}
+
+ ); + + const newIssue = ( +
+

Create new issue

+ Issue type: {activeIssueModificationRequest.nonratingIssueCategory}
+ Decision date: {formatDateStr(activeIssueModificationRequest.decisionDate)}
+ Issue description: {activeIssueModificationRequest.nonratingIssueDescription}
+
+ ); + + const modalInfo = { + [COPY.ISSUE_MODIFICATION_REQUESTS.MODIFICATION.REQUEST_TYPE]: ( +
+ {originalIssue} +
+ {newIssue} +
+ ) + }; + + const onSubmit = () => { + // Since this is being treated as a brand new request issue. The issue modification request + // no longer needs to retain references to the old request issue + const modifiedIssueRequest = { ...activeIssueModificationRequest, requestIssue: {}, requestIssueId: null }; + + // Update the pending issues data if any modification was made in the main modal + // this also updated the status to approved thus removing it from pending section. + dispatch(updatePendingReview(activeIssueModificationRequest.identifier, + modifiedIssueRequest)); + + const newFormattedRequestIssue = convertPendingIssueToRequestIssue(modifiedIssueRequest); + + dispatch(removeIssue(indexOfOriginalIssue)); + // Add the pending issue that is now a request issue to addedIssues + dispatch(addIssue(newFormattedRequestIssue)); + // close modal + dispatch(toggleConfirmPendingRequestIssueModal()); + }; + + return ( + dispatch(toggleConfirmPendingRequestIssueModal()) + }, + { + classNames: ['usa-button', 'usa-button-primary'], + name: 'Confirm', + onClick: onSubmit + } + ]} + closeHandler={() => dispatch(toggleConfirmPendingRequestIssueModal())} + > + {modalInfo[activeIssueModificationRequest.requestType]} + + ); +}; diff --git a/client/app/intake/components/IssueList.jsx b/client/app/intake/components/IssueList.jsx index 0529246c893..1a996eecc8d 100644 --- a/client/app/intake/components/IssueList.jsx +++ b/client/app/intake/components/IssueList.jsx @@ -5,7 +5,7 @@ import { FORM_TYPES } from '../constants'; import AddedIssue from './AddedIssue'; import Alert from 'app/components/Alert'; import Button from '../../components/Button'; -import Dropdown from '../../components/Dropdown'; +import SearchableDropdown from 'app/components/SearchableDropdown'; import EditContentionTitle from '../components/EditContentionTitle'; import { css } from 'glamor'; import { COLORS } from '../../constants/AppConstants'; @@ -31,42 +31,59 @@ export default class IssuesList extends React.Component { let options = []; if (issue.correctionType && issue.endProductCleared) { - options.push({ displayText: 'Undo correction', + options.push({ label: 'Undo correction', value: 'undo_correction' }); } else if (issue.correctionType && !issue.examRequested && docketType !== 'Legacy') { options.push( - { displayText: 'Remove issue', + { label: 'Remove issue', value: 'remove' } ); if (userCanEditIntakeIssues) { options.push( - { displayText: 'Edit issue', + { label: 'Edit issue', value: 'edit' } ); } } else if (issue.endProductCleared) { - options.push({ displayText: 'Correct issue', + options.push({ label: 'Correct issue', value: 'correct' }); } else if (!issue.examRequested && !issue.withdrawalDate && !issue.withdrawalPending && !isDtaError) { if (userCanWithdrawIssues && issue.id) { options.push( - { displayText: 'Withdraw issue', + { label: 'Withdraw issue', value: 'withdraw' } ); } if (docketType !== 'Legacy') { options.push( - { displayText: 'Remove issue', + { label: 'Remove issue', value: 'remove' } ); } if (userCanEditIntakeIssues) { options.push( - { displayText: 'Edit issue', + { label: 'Edit issue', value: 'edit' } ); } } + if (this.props.showRequestIssueUpdateOptions && this.props.intakeData.benefitType === 'vha') { + options = []; + options.push( + { label: 'Request modification', + value: 'requestModification' } + ); + + options.push( + { label: 'Request removal', + value: 'requestRemoval' } + ); + + options.push( + { label: 'Request withdrawal', + value: 'requestWithdrawal' } + ); + } const isIssueWithdrawn = issue.withdrawalDate || issue.withdrawalPending; @@ -74,7 +91,7 @@ export default class IssuesList extends React.Component { if ((!issue.date || issue.editedDecisionDate) && !isIssueWithdrawn && !issue.isUnidentified) { options.push( { - displayText: issue.editedDecisionDate ? 'Edit decision date' : 'Add decision date', + label: issue.editedDecisionDate ? 'Edit decision date' : 'Add decision date', value: 'add_decision_date' } ); @@ -93,7 +110,8 @@ export default class IssuesList extends React.Component { userCanWithdrawIssues, userCanEditIntakeIssues, editPage, - featureToggles + featureToggles, + disableIssueActions } = this.props; return
@@ -114,7 +132,9 @@ export default class IssuesList extends React.Component { const isIssueWithdrawn = issue.withdrawalDate || issue.withdrawalPending; const showNoDecisionDateBanner = !issue.date && !isIssueWithdrawn && - !issue.isUnidentified; + !issue.isUnidentified && !intakeData.isLegacy; + + const showNewIssueBasedOnRequestIssueBanner = issue.addedFromApprovedRequest; return
@@ -137,13 +157,17 @@ export default class IssuesList extends React.Component {
}
- {editPage && !_.isEmpty(issueActionOptions) && onClickIssueAction(issue.index, option)} + placeholder="Select action" + onChange={(option) => onClickIssueAction(issue.index, option.value)} + searchable={false} + doubleArrow + readOnly={disableIssueActions} /> } {!editPage &&
+
+
+
+
+ ); +}; + +export default CustomSeeds; diff --git a/client/app/testSeeds/components/SeedsBannerDisplay.jsx b/client/app/testSeeds/components/SeedsBannerDisplay.jsx new file mode 100644 index 00000000000..25940aaae87 --- /dev/null +++ b/client/app/testSeeds/components/SeedsBannerDisplay.jsx @@ -0,0 +1,24 @@ +import React from 'react'; +import Alert from '../../components/Alert'; + +const SeedsBannerDisplay = () => { + + let title = 'Test Seeds'; + let message = ''; + let type = 'success'; + let showBanner = false; + + return ( + <> + {showBanner && ( + + )} + + ); +}; + +export default SeedsBannerDisplay; diff --git a/client/app/testSeeds/components/TestSeedsWrapper.jsx b/client/app/testSeeds/components/TestSeedsWrapper.jsx new file mode 100644 index 00000000000..29edd3fa35a --- /dev/null +++ b/client/app/testSeeds/components/TestSeedsWrapper.jsx @@ -0,0 +1,12 @@ +import React from 'react'; +import CustomSeeds from './CustomSeeds'; + +const TestSeedsWrapper = () => { + return ( +
+ +
+ ); +}; + +export default TestSeedsWrapper; diff --git a/client/app/testSeeds/index.jsx b/client/app/testSeeds/index.jsx new file mode 100644 index 00000000000..69151501cad --- /dev/null +++ b/client/app/testSeeds/index.jsx @@ -0,0 +1,77 @@ +/* eslint-disable react/prop-types */ + +import React from 'react'; +import ReduxBase from '../components/ReduxBase'; +import NavigationBar from '../components/NavigationBar'; +import { BrowserRouter } from 'react-router-dom'; +import PageRoute from '../components/PageRoute'; +import AppFrame from '../components/AppFrame'; +import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/AppSegment'; +import { LOGO_COLORS } from '../constants/AppConstants'; +import Footer from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/Footer'; +import CaseSearchLink from '../components/CaseSearchLink'; +import SeedsBannerDisplay from './components/SeedsBannerDisplay'; +import rootReducer from '../testSeeds/reducers/root'; +import TestSeedsApp from './pages/TestSeedsApp'; + +class TestSeeds extends React.PureComponent { + + render() { + + const Router = this.props.router || BrowserRouter; + const appName = 'Test Seeds'; + + return ( + + +
+ } + appName="Caseflow Admin" + > + + + +
+ { + return ( + + ); + }} + /> +
+
+
+
+
+
+
+
+ ); + } +} + +export default TestSeeds; diff --git a/client/app/testSeeds/pages/TestSeedsApp.jsx b/client/app/testSeeds/pages/TestSeedsApp.jsx new file mode 100644 index 00000000000..3ed22e4a10d --- /dev/null +++ b/client/app/testSeeds/pages/TestSeedsApp.jsx @@ -0,0 +1,14 @@ +import React from 'react'; +import TestSeedsWrapper from '../components/TestSeedsWrapper'; + +const TestSeedsApp = () => { + return ( +
+
+ +
+
+ ); +}; + +export default TestSeedsApp; diff --git a/client/app/testSeeds/reducers/root.js b/client/app/testSeeds/reducers/root.js new file mode 100644 index 00000000000..0fad18bb724 --- /dev/null +++ b/client/app/testSeeds/reducers/root.js @@ -0,0 +1,12 @@ +import { timeFunction } from '../../util/PerfDebug'; +import { combineReducers } from 'redux'; +import seedsReducer from './seeds/seedsReducer'; + +const rootReducer = combineReducers({ + testSeeds: seedsReducer +}); + +export default timeFunction( + rootReducer, + (timeLabel, state, action) => `Action ${action.type} reducer time: ${timeLabel}` +); diff --git a/client/app/testSeeds/reducers/seeds/seedsActionTypes.js b/client/app/testSeeds/reducers/seeds/seedsActionTypes.js new file mode 100644 index 00000000000..846e194a011 --- /dev/null +++ b/client/app/testSeeds/reducers/seeds/seedsActionTypes.js @@ -0,0 +1,6 @@ +export const ACTIONS = { + ADD_CUSTOM_SEED: 'ADD_CUSTOM_SEED', + SAVE_CUSTOM_SEEDS: 'SAVE_CUSTOM_SEEDS', + REMOVE_CUSTOM_SEED: 'REMOVE_CUSTOM_SEED', + RESET_CUSTOM_SEEDS: 'RESET_CUSTOM_SEEDS' +}; diff --git a/client/app/testSeeds/reducers/seeds/seedsActions.js b/client/app/testSeeds/reducers/seeds/seedsActions.js new file mode 100644 index 00000000000..b8273f70b1c --- /dev/null +++ b/client/app/testSeeds/reducers/seeds/seedsActions.js @@ -0,0 +1,41 @@ +import { ACTIONS } from './seedsActionTypes'; +import ApiUtil from '../../../util/ApiUtil'; + + +export const addCustomSeed = (seed) => + (dispatch) => { + dispatch({ + type: ACTIONS.ADD_CUSTOM_SEED, + payload: { + seed + } + }); + }; + +export const removeCustomSeed = (seed, index) => + (dispatch) => { + dispatch({ + type: ACTIONS.REMOVE_CUSTOM_SEED, + payload: { + seed, + index + } + }); + }; + +export const resetCustomSeeds = () => + (dispatch) => { + dispatch({ + type: ACTIONS.RESET_CUSTOM_SEEDS + }); + }; + +export const saveCustomSeeds = (seeds) => + () => { + return ApiUtil.post('/seeds/run-demo', { data: seeds }).then(() => { + console.log("saved custom seed"); + }). + catch((err) => { + console.warn(err); + }); + }; diff --git a/client/app/testSeeds/reducers/seeds/seedsReducer.js b/client/app/testSeeds/reducers/seeds/seedsReducer.js new file mode 100644 index 00000000000..e079a973669 --- /dev/null +++ b/client/app/testSeeds/reducers/seeds/seedsReducer.js @@ -0,0 +1,38 @@ +import { ACTIONS } from '../seeds/seedsActionTypes'; +import { update } from '../../../util/ReducerUtil'; + + +// Refactor where it is used before deletion +export const initialState = { + seeds: [], + displayBanner: false +}; + +const seedsReducer = (state = initialState, action = {}) => { + switch (action.type) { + case ACTIONS.ADD_CUSTOM_SEED: + return { + ...state, + seeds: [...state.seeds, action.payload.seed] + }; + case ACTIONS.REMOVE_CUSTOM_SEED: + return { + ...state, + seeds: state.seeds.filter((_, index) => index !== action.payload.index) + }; + case ACTIONS.SAVE_CUSTOM_SEEDS: + return { + ...state, + displayBanner: true + }; + case ACTIONS.RESET_CUSTOM_SEEDS: + return { + ...state, + seeds: [] + }; + default: + return state; + } +}; + +export default seedsReducer; diff --git a/client/app/util/NetworkUtil.js b/client/app/util/NetworkUtil.js new file mode 100644 index 00000000000..b2423f3b26e --- /dev/null +++ b/client/app/util/NetworkUtil.js @@ -0,0 +1,39 @@ +// NetworkUtil.js + +class NetworkUtil { + constructor() { + this.bandwidth = null; + } + + async getConnectionInfo() { + try { + if ('connection' in navigator) { + const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; + + // Update network details during connectionInfo() + this.bandwidth = connection.downlink; + } else { + // eslint-disable-next-line no-console + console.log('Network Information API not supported in this browser'); + } + } catch (error) { + // eslint-disable-next-line no-console + console.error('Error getting connection info:', error); + } + } + + async connectionInfo() { + await this.getConnectionInfo(); + + // Handle case where bandwidth is not set + if (this.bandwidth === null) { + return 'Not available'; + } + + return `${this.bandwidth} Mbits/s`; + } +} + +const networkUtil = new NetworkUtil(); + +export default networkUtil; diff --git a/client/constants/ACD_LEVERS.json b/client/constants/ACD_LEVERS.json index ca73b8769bc..92eb0942637 100644 --- a/client/constants/ACD_LEVERS.json +++ b/client/constants/ACD_LEVERS.json @@ -4,6 +4,8 @@ "value": "value", "days": "days", "cases": "cases", + "priority": "priority", + "non_priority": "non-priority", "DUPLICATE": "DUPLICATE", "ERROR": "ERROR", "data_types": { diff --git a/client/constants/CUSTOM_SEEDS.json b/client/constants/CUSTOM_SEEDS.json new file mode 100644 index 00000000000..9c7ac4fa84f --- /dev/null +++ b/client/constants/CUSTOM_SEEDS.json @@ -0,0 +1,6 @@ +{ + "ama-aod-hearing-seeds": "Seed AMA AOD Hearing", + "ama-non-aod-hearing-seeds": "Seed AMA NON AOD Hearing", + "legacy-case-seeds": "Seed Legacy Cases", + "ama-direct-review-seeds": "Seed AMA Direct Review" +} diff --git a/client/constants/DISTRIBUTION.json b/client/constants/DISTRIBUTION.json index dd6df8f92ee..d4b1809cd9c 100644 --- a/client/constants/DISTRIBUTION.json +++ b/client/constants/DISTRIBUTION.json @@ -13,10 +13,10 @@ "aoj_affinity_days": "aoj_affinity_days", "aoj_aod_affinity_days": "aoj_aod_affinity_days", "aoj_cavc_affinity_days": "aoj_cavc_affinity_days", - "ama_hearings_start_distribution_prior_to_goals": "ama_hearings_start_distribution_prior_to_goals", + "ama_hearing_start_distribution_prior_to_goals": "ama_hearing_start_distribution_prior_to_goals", "ama_direct_review_start_distribution_prior_to_goals": "ama_direct_review_start_distribution_prior_to_goals", "ama_evidence_submission_start_distribution_prior_to_goals": "ama_evidence_submission_start_distribution_prior_to_goals", - "ama_hearings_docket_time_goals": "ama_hearings_docket_time_goals", + "ama_hearing_docket_time_goals": "ama_hearing_docket_time_goals", "ama_direct_review_docket_time_goals": "ama_direct_review_docket_time_goals", "ama_evidence_submission_docket_time_goals": "ama_evidence_submission_docket_time_goals", "days_before_goal_due_for_distribution": "days_before_goal_due_for_distribution", @@ -39,20 +39,20 @@ "alternative_batch_size_title": "Alternate Batch Size", "batch_size_per_attorney_title": "Batch Size Per Attorney", "request_more_cases_minimum_title": "Request More Cases Minimum", - "disable_legacy_priority": "ACD Disable Legacy Priority" , + "disable_legacy_priority": "disable_legacy_priority", "disable_legacy_priority_title": "ACD Disable Legacy Priority", - "disable_legacy_non_priority": "ACD Disable Legacy Non-priority" , + "disable_legacy_non_priority": "disable_legacy_non_priority", "disable_legacy_non_priority_title": "ACD Disable Legacy Non-priority", - "disable_ama_non_priority_hearing": "ACD Disable AMA Non-Priority Hearing" , + "disable_ama_non_priority_hearing": "disable_ama_non_priority_hearing", "disable_ama_non_priority_hearing_title": "ACD Disable AMA Non-Priority Hearing", - "disable_ama_non_priority_direct_review": "ACD Disable AMA Non-Priority Direct Review" , + "disable_ama_non_priority_direct_review": "disable_ama_non_priority_direct_review", "disable_ama_non_priority_direct_review_title": "ACD Disable AMA Non-Priority Direct Review", - "disable_ama_non_priority_evidence_sub": "ACD Disable AMA Non-Priority Evidence Submission" , - "disable_ama_non_priority_evidence_sub_title": "ACD Disable AMA Non-Priority Evidence Submission", - "disable_ama_priority_hearing": "ACD Disable AMA Priority Hearing" , + "disable_ama_non_priority_evidence_submission": "disable_ama_non_priority_evidence_submission", + "disable_ama_non_priority_evidence_submission_title": "ACD Disable AMA Non-Priority Evidence Submission", + "disable_ama_priority_hearing": "disable_ama_priority_hearing", "disable_ama_priority_hearing_title": "ACD Disable AMA Priority Hearing", - "disable_ama_priority_direct_review": "ACD Disable AMA Priority Direct Review" , + "disable_ama_priority_direct_review": "disable_ama_priority_direct_review", "disable_ama_priority_direct_review_title": "ACD Disable AMA Priority Direct Review", - "disable_ama_priority_evidence_sub": "ACD Disable AMA Priority Evidence Submission" , - "disable_ama_priority_evidence_sub_title": "ACD Disable AMA Priority Evidence Submission" + "disable_ama_priority_evidence_submission": "disable_ama_priority_evidence_submission", + "disable_ama_priority_evidence_submission_title": "ACD Disable AMA Priority Evidence Submission" } diff --git a/client/constants/QUEUE_CONFIG.json b/client/constants/QUEUE_CONFIG.json index 41889f81867..a2711919cf9 100644 --- a/client/constants/QUEUE_CONFIG.json +++ b/client/constants/QUEUE_CONFIG.json @@ -26,19 +26,15 @@ "SPECIALTY_CASE_TEAM_ACTION_REQUIRED_TASKS_TAB_NAME": "sct_action_required", "SPECIALTY_CASE_TEAM_COMPLETED_TASKS_TAB_NAME": "sct_completed", "SPECIALTY_CASE_TEAM_UNASSIGNED_TASKS_TAB_NAME": "sct_unassigned", - "EDUCATION_RPO_ASSIGNED_TASKS_TAB_NAME": "education_rpo_assigned", "EDUCATION_RPO_IN_PROGRESS_TASKS_TAB_NAME": "education_rpo_in_progress", "EDUCATION_RPO_COMPLETED_TASKS_TAB_NAME": "education_rpo_completed", - "EDUCATION_EMO_UNASSIGNED_TASKS_TAB_NAME": "education_emo_unassigned", "EDUCATION_EMO_ASSIGNED_TASKS_TAB_NAME": "education_emo_assigned", "EDUCATION_EMO_COMPLETED_TASKS_TAB_NAME": "education_emo_completed", - "CAREGIVER_SUPPORT_UNASSIGNED_TASK_TAB_NAME": "vha_caregiver_support_unassigned", "CAREGIVER_SUPPORT_IN_PROGRESS_TASKS_TAB_NAME": "caregiver_support_in_progress", "CAREGIVER_SUPPORT_COMPLETED_TASKS_TAB_NAME": "caregiver_support_completed", - "COLUMNS": { "APPEAL_TYPE": { "filterable": true, @@ -47,12 +43,16 @@ "BOARD_INTAKE": { "name": "boardIntakeColumn", "sorting_table": "tasks", - "sorting_columns": ["assigned_at"] + "sorting_columns": [ + "assigned_at" + ] }, "CASE_DETAILS_LINK": { "name": "detailsColumn", "sorting_table": "cached_appeal_attributes", - "sorting_columns": ["veteran_name"] + "sorting_columns": [ + "veteran_name" + ] }, "DAYS_ON_HOLD": { "name": "daysOnHoldColumn" @@ -73,7 +73,9 @@ "DAYS_WAITING": { "name": "daysWaitingColumn", "sorting_table": "tasks", - "sorting_columns": ["assigned_at"] + "sorting_columns": [ + "assigned_at" + ] }, "LAST_ACTION": { "name": "lastActionColumn" @@ -82,7 +84,10 @@ "filterable": true, "name": "docketNumberColumn", "sorting_table": "cached_appeal_attributes", - "sorting_columns": ["docket_type", "docket_number"] + "sorting_columns": [ + "docket_type", + "docket_number" + ] }, "DOCUMENT_COUNT_READER_LINK": { "name": "readerLinkColumn" @@ -96,10 +101,15 @@ "CLAIMANT_NAME": { "name": "claimantColumn" }, + "PENDING_ISSUE_MODIFICATION_COUNT": { + "name": "pendingIssueModificationRequests" + }, "ISSUE_COUNT": { "name": "issueCountColumn", "sorting_table": "cached_appeal_attributes", - "sorting_columns": ["issue_count"] + "sorting_columns": [ + "issue_count" + ] }, "ISSUE_TYPES": { "filterable": true, @@ -122,13 +132,17 @@ "filterable": true, "name": "regionalOfficeColumn", "sorting_table": "cached_appeal_attributes", - "sorting_columns": ["closest_regional_office_city"] + "sorting_columns": [ + "closest_regional_office_city" + ] }, "TASK_ASSIGNEE": { "filterable": true, "name": "assignedToColumn", "sorting_table": "assignees", - "sorting_columns": ["display_name"] + "sorting_columns": [ + "display_name" + ] }, "TASK_ASSIGNER": { "name": "completedToNameColumn" @@ -139,55 +153,71 @@ "TASK_CLOSED_DATE": { "name": "completedDateColumn", "sorting_table": "tasks", - "sorting_columns": ["closed_at"] + "sorting_columns": [ + "closed_at" + ] }, "TASK_CREATED_AT": { "name": "createdDateColumn", "sorting_table": "tasks", - "sorting_columns": ["created_at"] + "sorting_columns": [ + "created_at" + ] }, "TASK_DUE_DATE": { "name": "caseDueDateColumn", "sorting_table": "tasks", - "sorting_columns": ["assigned_at"] + "sorting_columns": [ + "assigned_at" + ] }, "TASK_HOLD_LENGTH": { "name": "caseDaysOnHoldColumn", "sorting_table": "tasks", - "sorting_columns": ["placed_on_hold_at"] + "sorting_columns": [ + "placed_on_hold_at" + ] }, "TASK_OWNER": { "name": "taskOwnerColumn", "sorting_table": "assignees", - "sorting_columns": ["type", "action", "created_at"] + "sorting_columns": [ + "type", + "action", + "created_at" + ] }, "TASK_TYPE": { "filterable": true, "name": "taskColumn", "sorting_table": "tasks", - "sorting_columns": ["type", "action", "created_at"] + "sorting_columns": [ + "type", + "action", + "created_at" + ] }, "VAMC_OWNER": { "name": "vamcOwnerColumn", "sorting_table": "assignees", - "sorting_columns": ["type", "action", "created_at"] + "sorting_columns": [ + "type", + "action", + "created_at" + ] } }, - "TAB_NAME_REQUEST_PARAM": "tab", "PAGE_NUMBER_REQUEST_PARAM": "page", "SORT_COLUMN_REQUEST_PARAM": "sort_by", "SORT_DIRECTION_REQUEST_PARAM": "order", "FILTER_COLUMN_REQUEST_PARAM": "filter", "SEARCH_QUERY_REQUEST_PARAM": "search_query", - "COLUMN_SORT_ORDER_ASC": "asc", "COLUMN_SORT_ORDER_DESC": "desc", - "DEFAULT_SORTING_COLUMN_KEY": "sortColName", "DEFAULT_SORTING_DIRECTION_KEY": "sortAscending", "BLANK_FILTER_KEY_VALUE": "None", - "FILTER_OPTIONS": { "IS_AOD": { "key": "is_aod" diff --git a/client/constants/REGIONAL_OFFICE_FACILITY_ADDRESS.json b/client/constants/REGIONAL_OFFICE_FACILITY_ADDRESS.json index 69e4ba51be3..b3eef126fd4 100644 --- a/client/constants/REGIONAL_OFFICE_FACILITY_ADDRESS.json +++ b/client/constants/REGIONAL_OFFICE_FACILITY_ADDRESS.json @@ -1085,7 +1085,7 @@ "address_1" : "913 Northwest Garden Valley Boulevard", "address_2" : null, "address_3" : null, - "city" : "Rosenburg", + "city" : "Roseburg", "state" : "OR", "zip" : "97471-6523", "timezone" : "America/Los_Angeles" @@ -1100,7 +1100,7 @@ "timezone" : "America/Los_Angeles" }, "vha_653GA" : { - "address_1" : "2191 Marion Street", + "address_1" : "2191 Marion Ave", "address_2" : "", "address_3" : null, "city" : "North Bend", @@ -1117,6 +1117,15 @@ "zip" : "97415-9702", "timezone" : "America/Los_Angeles" }, + "vha_653QA" : { + "address_1" : "211 E 7th Ave", + "address_2" : null, + "address_3" : "Suite 118", + "city" : "Eugene", + "state" : "OR", + "zip" : "97401", + "timezone" : "America/Los_Angeles" + }, "vha_657GJ" : { "address_1" : "6211 East Waterford Boulevard", "address_2" : null, @@ -1297,6 +1306,15 @@ "zip" : "97601-6417", "timezone" : "America/Los_Angeles" }, + "vha_692GB" : { + "address_1" : "1877 Williams Hwy", + "address_2" : null, + "address_3" : null, + "city" : "Grants Pass", + "state" : "OR", + "zip" : "97527", + "timezone" : "America/Los_Angeles" + }, "vha_693" : { "address_1" : "1111 East End Boulevard", "address_2" : null, diff --git a/client/constants/REGIONAL_OFFICE_INFORMATION.json b/client/constants/REGIONAL_OFFICE_INFORMATION.json index 1483d4ce0ca..c95694b0b53 100644 --- a/client/constants/REGIONAL_OFFICE_INFORMATION.json +++ b/client/constants/REGIONAL_OFFICE_INFORMATION.json @@ -477,6 +477,7 @@ "alternate_locations": [ "vha_653", "vha_653BY", + "vha_653QA", "vba_347", "vha_653GB", "vha_648GA", @@ -484,7 +485,8 @@ "vha_687GC", "vha_653GA", "vba_346", - "vha_692" + "vha_692", + "vha_692GB" ] }, "RO49": { diff --git a/client/constants/TEST_SEEDS.json b/client/constants/TEST_SEEDS.json new file mode 100644 index 00000000000..5744f7c7ad6 --- /dev/null +++ b/client/constants/TEST_SEEDS.json @@ -0,0 +1,10 @@ +{ + "aod-seeds": "db:seed:demo_aod_hearing_case_lever_test_data", + "non-aod-hearing-seeds":"db:seed:demo_non_aod_hearing_case_lever_test_data", + "ama-aod-hearing-seeds": "db:seed:demo_ama_aod_hearing_data", + "ama-non-aod-hearing-seeds": "db:seed:demo_ama_non_aod_hearing_data", + "legacy-case-seeds": "db:seed:demo_legacy_cases_data", + "ama-direct-review-seeds": "db:seed:demo_direct_reviews_data", + "scenario-1-seeds": "db:seed:demo_aod_hearing_case_lever_test_data", + "scenario-2-seeds": "db:seed:demo_non_aod_hearing_case_lever_test_data" +} diff --git a/client/test/app/caseDistribution/components/DocketTimeGoals.test.js b/client/test/app/caseDistribution/components/DocketTimeGoals.test.js index cffa7862b25..fd5ff9ab9bf 100644 --- a/client/test/app/caseDistribution/components/DocketTimeGoals.test.js +++ b/client/test/app/caseDistribution/components/DocketTimeGoals.test.js @@ -59,8 +59,8 @@ describe('Docket Time Goals Lever', () => { ); - let leverTimeGoal = wrapper.find('input[name="ama_hearings_docket_time_goals"]'); - let leverDistPrior = wrapper.find('input[name="ama_hearings_start_distribution_prior_to_goals"]'); + let leverTimeGoal = wrapper.find('input[name="ama_hearing_docket_time_goals"]'); + let leverDistPrior = wrapper.find('input[name="ama_hearing_start_distribution_prior_to_goals"]'); waitFor(() => expect(leverTimeGoal).toHaveTextContent(testTimeGoalLever.value)); waitFor(() => expect(leverDistPrior).toHaveTextContent(testDistPriorLever.value)); diff --git a/client/test/app/caseDistribution/components/ExcludeDocketLever.test.js b/client/test/app/caseDistribution/components/ExcludeDocketLever.test.js new file mode 100644 index 00000000000..2d098874be0 --- /dev/null +++ b/client/test/app/caseDistribution/components/ExcludeDocketLever.test.js @@ -0,0 +1,73 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import ExcludeDocketLever from 'app/caseDistribution/components/ExcludeDocketLever'; +import { Provider } from 'react-redux'; +import { createStore, applyMiddleware } from 'redux'; +import rootReducer from 'app/caseDistribution/reducers/root'; +import thunk from 'redux-thunk'; +import { mockDocketLevers } from '../../../data/adminCaseDistributionLevers'; +import { loadLevers, setUserIsAcdAdmin } from 'app/caseDistribution/reducers/levers/leversActions'; + +describe('Exclusion Lever', () => { + + const getStore = () => createStore( + rootReducer, + applyMiddleware(thunk)); + + afterEach(() => { + jest.clearAllMocks(); + }); + let lever = mockDocketLevers[0]; + + let selectedLever = { + displayText: lever.title, + item: lever.item, + value: lever.value, + disabled: lever.is_disabled_in_ui, + options: lever.options, + leverGroup: lever.lever_group, + }; + + let leversWithTestingDocketLevers = { docket_levers: mockDocketLevers }; + + it('Exclusion Lever Renders', () => { + const store = getStore(); + + store.dispatch(loadLevers(leversWithTestingDocketLevers)); + store.dispatch(setUserIsAcdAdmin(false)); + + const wrapper = mount(( + + + )); + + let input = (wrapper.find('input').at(1)); + + // All 8 levers are rendered + expect(wrapper).toBeDefined(); + expect(input.instance().value).toBe('false'); + }); + + it('Exclusion Lever Change Value', () => { + const store = getStore(); + + store.dispatch(loadLevers(leversWithTestingDocketLevers)); + store.dispatch(setUserIsAcdAdmin(false)); + + const wrapper = mount(( + + + )); + + let input = (wrapper.find('input').at(0)); + + input.simulate('change', { lever, event: { value: true } }); + + expect(input.instance().value).toBeTruthy(); + }); + +}); diff --git a/client/test/app/caseDistribution/components/ExclusionTable.test.js b/client/test/app/caseDistribution/components/ExclusionTable.test.js new file mode 100644 index 00000000000..453b1977ccf --- /dev/null +++ b/client/test/app/caseDistribution/components/ExclusionTable.test.js @@ -0,0 +1,53 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import RadioField from 'app/components/RadioField'; +import ExclusionTable from 'app/caseDistribution/components/ExclusionTable'; +import { Provider } from 'react-redux'; +import { createStore, applyMiddleware } from 'redux'; +import rootReducer from 'app/caseDistribution/reducers/root'; +import thunk from 'redux-thunk'; +import { mockDocketLevers } from '../../../data/adminCaseDistributionLevers'; +import { loadLevers, setUserIsAcdAdmin } from 'app/caseDistribution/reducers/levers/leversActions'; + +describe('Exclusion Table', () => { + + const getStore = () => createStore( + rootReducer, + applyMiddleware(thunk)); + + afterEach(() => { + jest.clearAllMocks(); + }); + + let leversWithTestingDocketLevers = { docket_levers: mockDocketLevers }; + + it('Exclusion Table Renders all 8 Levers as Admin', () => { + const store = getStore(); + + store.dispatch(loadLevers(leversWithTestingDocketLevers)); + store.dispatch(setUserIsAcdAdmin(true)); + + const wrapper = mount(( + + + )); + + expect(wrapper.find(RadioField)).toHaveLength(8); + }); + + it('Exclusion Table Renders all 8 Levers for Member View', () => { + const store = getStore(); + + store.dispatch(loadLevers(leversWithTestingDocketLevers)); + store.dispatch(setUserIsAcdAdmin(false)); + + const wrapper = mount(( + + + )); + + // Renders all 8 Lever Labels + expect(wrapper.find('.exclusion-table-member-view-styling').length).toBe(8); + }); + +}); diff --git a/client/test/app/caseDistribution/reducers/levers/LeversReducer.test.js b/client/test/app/caseDistribution/reducers/levers/LeversReducer.test.js index ddabfc370b6..741dadfc08f 100644 --- a/client/test/app/caseDistribution/reducers/levers/LeversReducer.test.js +++ b/client/test/app/caseDistribution/reducers/levers/LeversReducer.test.js @@ -145,14 +145,14 @@ describe('Lever reducer', () => { type: ACTIONS.UPDATE_LEVER_IS_TOGGLE_ACTIVE, payload: { leverGroup: 'docket_distribution_prior', - leverItem: 'ama_hearings_start_distribution_prior_to_goals', + leverItem: 'ama_hearing_start_distribution_prior_to_goals', toggleValue: false } }; const combinationLevers = initialState.levers.docket_distribution_prior; const updatedCombinationLevers = combinationLevers.map((lever) => { - if (lever.item === 'ama_hearings_start_distribution_prior_to_goals') { + if (lever.item === 'ama_hearing_start_distribution_prior_to_goals') { return { ...lever, is_toggle_active: false diff --git a/client/test/app/components/__snapshots__/Modal.test.js.snap b/client/test/app/components/__snapshots__/Modal.test.js.snap index 1f0dd792341..023f7c9c241 100644 --- a/client/test/app/components/__snapshots__/Modal.test.js.snap +++ b/client/test/app/components/__snapshots__/Modal.test.js.snap @@ -43,23 +43,20 @@ exports[`Modal renders correctly 1`] = `
+

+ Test Modal Title +

-

- Test Modal Title -

-
-

- This is text content -

-
+

+ This is text content +

{ +/* eslint-disable jest/no-disabled-tests */ +describe.skip('ScheduleVeteranForm', () => { test('Matches snapshot with default props', () => { // Render the address component const scheduleVeteran = mount( diff --git a/client/test/app/hearings/components/__snapshots__/EditUnscheduledNotesModal.test.js.snap b/client/test/app/hearings/components/__snapshots__/EditUnscheduledNotesModal.test.js.snap index 79b967927ef..7f8b84c3d60 100644 --- a/client/test/app/hearings/components/__snapshots__/EditUnscheduledNotesModal.test.js.snap +++ b/client/test/app/hearings/components/__snapshots__/EditUnscheduledNotesModal.test.js.snap @@ -43,41 +43,38 @@ exports[`EditUnscheduledNotesModal renders correctly 1`] = `
+

+ Edit Notes +

-

- Edit Notes -

-
-
-
+
+
+
+ + +
+

+ Add Court dates +

-

- Add Court dates -

+

+ Complete the details below to intake this Court remand for further processing +

-

- Complete the details below to intake this Court remand for further processing -

-
- -
- -
-
+ + + What is the Court's judgement date? + + +
- -
- -
+
+
+
+
- - +
+
+ + +
+

+ Review extension request +

-

- Review extension request -

-
- -
+ + + How will you proceed? + + + + +
- - - - How will you proceed? - - - -
-
+
-
+ - - - + +
+
+ + + +
-
- Marks the extension request as denied -
- -
+ Marks the extension request as denied +
+
-
-
- + + + +
-
- -