Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Issue #97853 Add Power of Attorney Request Models, Factories, and Specs #19919

Merged
merged 10 commits into from
Dec 19, 2024

Conversation

ojbucao
Copy link
Contributor

@ojbucao ojbucao commented Dec 16, 2024

This PR introduces the core components for the Power of Attorney Request feature, ensuring a complete and testable implementation. Each model is accompanied by its corresponding factory for test data generation and RSpec tests for verification.

  1. Models
    • PowerOfAttorneyRequest
    • PowerOfAttorneyForm
    • PowerOfAttorneyRequestDecision
    • PowerOfAttorneyRequestExpiration
    • PowerOfAttorneyRequestResolution
  2. Factories
    • Added factories for generating test data for the above models.
  3. RSpec Tests
    • Added unit tests to validate model behaviors and associations.

@ojbucao ojbucao requested review from nihil2501 and chumpy December 16, 2024 22:14
@va-vfs-bot va-vfs-bot temporarily deployed to art/97853/mvp-poa-reqs-models/main/main December 16, 2024 22:35 Inactive
Copy link

github-actions bot commented Dec 16, 2024

1 Warning
⚠️ This PR changes 287 LoC (not counting whitespace/newlines).

In order to ensure each PR receives the proper attention it deserves, we recommend not exceeding
200. Expect some delays getting reviews.

File Summary

Files

  • modules/accredited_representative_portal/accredited_representative_portal.gemspec (+1/-0)

  • modules/accredited_representative_portal/app/models/accredited_representative_portal/power_of_attorney_form.rb (+12/-0)

  • modules/accredited_representative_portal/app/models/accredited_representative_portal/power_of_attorney_request.rb (+11/-0)

  • modules/accredited_representative_portal/app/models/accredited_representative_portal/power_of_attorney_request_decision.rb (+8/-0)

  • modules/accredited_representative_portal/app/models/accredited_representative_portal/power_of_attorney_request_expiration.rb (+5/-0)

  • modules/accredited_representative_portal/app/models/accredited_representative_portal/power_of_attorney_request_resolution.rb (+20/-0)

  • modules/accredited_representative_portal/lib/accredited_representative_portal/engine.rb (+5/-0)

  • modules/accredited_representative_portal/spec/factories/power_of_attorney_decision.rb (+8/-0)

  • modules/accredited_representative_portal/spec/factories/power_of_attorney_expiration.rb (+6/-0)

  • modules/accredited_representative_portal/spec/factories/power_of_attorney_form.rb (+10/-0)

  • modules/accredited_representative_portal/spec/factories/power_of_attorney_request.rb (+7/-0)

  • modules/accredited_representative_portal/spec/factories/power_of_attorney_request_resolution.rb (+37/-0)

  • modules/accredited_representative_portal/spec/models/accredited_representative_portal/power_of_attorney_form_spec.rb (+12/-0)

  • modules/accredited_representative_portal/spec/models/accredited_representative_portal/power_of_attorney_request_decision_spec.rb (+7/-0)

  • modules/accredited_representative_portal/spec/models/accredited_representative_portal/power_of_attorney_request_expiration_spec.rb (+12/-0)

  • modules/accredited_representative_portal/spec/models/accredited_representative_portal/power_of_attorney_request_resolution_spec.rb (+118/-0)

  • modules/accredited_representative_portal/spec/models/accredited_representative_portal/power_of_attorney_request_spec.rb (+8/-0)

    Note: We exclude files matching the following when considering PR size:

    *.csv, *.json, *.tsv, *.txt, *.md, Gemfile.lock, app/swagger, modules/mobile/docs, spec/fixtures/, spec/support/vcr_cassettes/, modules/mobile/spec/support/vcr_cassettes/, db/seeds, modules/vaos/app/docs, modules/meb_api/app/docs, modules/appeals_api/app/swagger/, *.bru, *.pdf
    

Big PRs are difficult to review, often become stale, and cause delays.

Generated by 🚫 Danger

@va-vfs-bot va-vfs-bot temporarily deployed to art/97853/mvp-poa-reqs-models/main/main December 16, 2024 23:18 Inactive
@nihil2501 nihil2501 changed the base branch from master to art/96235/mvp-poa-reqs-migrations December 17, 2024 04:05
@va-vfs-bot va-vfs-bot temporarily deployed to art/97853/mvp-poa-reqs-models/main/main December 17, 2024 04:06 Inactive
@nihil2501 nihil2501 changed the base branch from art/96235/mvp-poa-reqs-migrations to master December 17, 2024 04:07
@nihil2501
Copy link
Contributor

@ojbucao Let's use "Pull Request Stacks" so that these are easy to review. If you're building off of the work of a previous branch branch-1, it makes sense to branch off of that branch branch-2 and then open a PR branch-1 <- branch-2.

@va-vfs-bot va-vfs-bot temporarily deployed to art/97853/mvp-poa-reqs-models/main/main December 17, 2024 04:15 Inactive
Copy link
Contributor

@nihil2501 nihil2501 left a comment

Choose a reason for hiding this comment

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

  • we should question use of validates
  • i think we should consider subbing in DB defined cascading (unfortunately not exposed in add_reference but is exposed in add_foreign_key; sigh) and avoid doing meaningful work in model lifecycle callbacks (sorry, Rails made a mess in these areas)
  • please get in the habit of making PR stacks. these are hard to review otherwise. GH treats PR stacks conveniently, when stacked PR's base branch merges to main, dependent PR updates its base branch
  • power_of_attorney_form

Comment on lines 20 to 22
validates :city_bidx, presence: true, length: { is: 44 }
validates :state_bidx, presence: true, length: { is: 44 }
validates :zipcode_bidx, presence: true, length: { is: 44 }
Copy link
Contributor

Choose a reason for hiding this comment

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

why length?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's the length of the cryptographic hash that results.

blind_index :zipcode

# Validations
validates :power_of_attorney_request_id, uniqueness: true
Copy link
Contributor

Choose a reason for hiding this comment

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

See discussion on race conditions when checking uniqueness from ActiveRecord. Since this uniqueness constraint is not something a user can cause by their input, I don't think there is added benefit to implementing this with validations (which are convenient because they can collect issues for feedback for the user, but that's not our situation). Also, the PG adapter surfaces the RecordNotUnique exception, so we'll know what's up.

Comment on lines 19 to 22
validates :data_ciphertext, presence: true
validates :city_bidx, presence: true, length: { is: 44 }
validates :state_bidx, presence: true, length: { is: 44 }
validates :zipcode_bidx, presence: true, length: { is: 44 }
Copy link
Contributor

Choose a reason for hiding this comment

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

None of these are really controlled by user input and there's nowhere they ought to be shown back to the user. If these aren't valid it's a programming bug we caused and these have not null constraints in the DB.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense. I'll go ahead and remove them.

belongs_to :claimant,
class_name: 'UserAccount'

has_one :form,
Copy link
Contributor

Choose a reason for hiding this comment

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

power_of_attorney_form

class PowerOfAttorneyForm < ApplicationRecord
belongs_to :power_of_attorney_request,
class_name: 'AccreditedRepresentativePortal::PowerOfAttorneyRequest',
inverse_of: :form
Copy link
Contributor

Choose a reason for hiding this comment

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

power_of_attorney_form

There is a meaningful semantic difference between poa form and poa request form. The latter doesn't make sense. A poa request will result in a poa form being made. It's marginal but I think leans this way a little.

belongs_to :creator,
class_name: 'UserAccount'

has_one :power_of_attorney_request_resolution,
Copy link
Contributor

Choose a reason for hiding this comment

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

Follow delegated type pattern with mixin. Good example in my sketch PR.


has_one :power_of_attorney_request_resolution,
as: :resolving,
inverse_of: :resolving,
Copy link
Contributor

Choose a reason for hiding this comment

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

didn't look close but does inverse_of work in the polymorphic case? i'll look closer upon refinement of this PR if necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you're right. my bad. removing it.

class PowerOfAttorneyRequestExpiration < ApplicationRecord
has_one :power_of_attorney_request_resolution,
as: :resolving,
inverse_of: :resolving,
Copy link
Contributor

Choose a reason for hiding this comment

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

didn't look close but does inverse_of work in the polymorphic case? i'll look closer upon refinement of this PR if necessary.

Comment on lines 10 to 11
# Validations
validates :id, presence: true
Copy link
Contributor

Choose a reason for hiding this comment

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

validates :id, presence: true is something i've never seen before. I think it shouldn't be there.

@nihil2501
Copy link
Contributor

@ojbucao I didn't review the fixtures and model specs really yet.

@ojbucao ojbucao force-pushed the art/97853/mvp-poa-reqs-models branch from 3448bd9 to 1c3df00 Compare December 17, 2024 20:21
@va-vfs-bot va-vfs-bot temporarily deployed to art/97853/mvp-poa-reqs-models/main/main December 17, 2024 20:43 Inactive
@ojbucao ojbucao force-pushed the art/97853/mvp-poa-reqs-models branch from 1c3df00 to 6024452 Compare December 17, 2024 20:46
@va-vfs-bot va-vfs-bot temporarily deployed to art/97853/mvp-poa-reqs-models/main/main December 17, 2024 21:02 Inactive
@va-vfs-bot va-vfs-bot temporarily deployed to art/97853/mvp-poa-reqs-models/main/main December 17, 2024 23:28 Inactive
@ojbucao ojbucao force-pushed the art/97853/mvp-poa-reqs-models branch from 7ec1183 to af04c9a Compare December 18, 2024 00:03
@va-vfs-bot va-vfs-bot temporarily deployed to art/97853/mvp-poa-reqs-models/main/main December 18, 2024 00:05 Inactive
Copy link
Contributor

@nihil2501 nihil2501 left a comment

Choose a reason for hiding this comment

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

small changes, then this is ready to go:

  • resolving not optional
    • if there were issues here, maybe this way of creating both objects simultaneously is what we should have?
  • i don't think we need any of the validates
  • don't need dependent: :destroy, we can do cascading deletes in the db

but let me know if you think i'm mistaken somewhere

'AccreditedRepresentativePortal::PowerOfAttorneyRequestDecision'
].freeze

delegated_type :resolving, types: RESOLVING_TYPES, dependent: :destroy, optional: true
Copy link
Contributor

Choose a reason for hiding this comment

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

not optional.

Copy link
Contributor

Choose a reason for hiding this comment

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

in a follow up commit we can implement all the foreign key cascades and in this case maybe a trigger. let's remove AR's handling of this with dependent

has_one(
:power_of_attorney_request_resolution,
as: :resolving,
touch: true
Copy link
Contributor

Choose a reason for hiding this comment

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

looked up the touch option and it's for updated timestamps which the sub types don't have so we can remove this

Comment on lines 20 to 22
# Validations
validates :resolving_type, presence: true, inclusion: { in: RESOLVING_TYPES, allow_nil: true }
validates :resolving_id, presence: true, if: -> { resolving_type.present? }
Copy link
Contributor

Choose a reason for hiding this comment

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

won't need this since association isn't optional

@ojbucao ojbucao force-pushed the art/97853/mvp-poa-reqs-models branch 2 times, most recently from 3252ccf to 3815598 Compare December 18, 2024 17:53
@va-vfs-bot va-vfs-bot temporarily deployed to art/97853/mvp-poa-reqs-models/main/main December 18, 2024 18:23 Inactive
@ojbucao ojbucao force-pushed the art/97853/mvp-poa-reqs-models branch from 3815598 to f56149d Compare December 19, 2024 00:31
@va-vfs-bot va-vfs-bot temporarily deployed to art/97853/mvp-poa-reqs-models/main/main December 19, 2024 00:33 Inactive
Copy link
Contributor

@nihil2501 nihil2501 left a comment

Choose a reason for hiding this comment

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

LGTM

@ojbucao ojbucao marked this pull request as ready for review December 19, 2024 00:34
@ojbucao ojbucao requested review from a team as code owners December 19, 2024 00:34
@ojbucao ojbucao merged commit 365ef65 into master Dec 19, 2024
23 checks passed
@ojbucao ojbucao deleted the art/97853/mvp-poa-reqs-models branch December 19, 2024 17:22
derekhouck pushed a commit that referenced this pull request Dec 31, 2024
…cs (#19919)

* (feat) Add PowerOfAttorneyRequest model, factory, and specs

* (feat) Add PowerOfAttorneyRequestDecision model, factory, and specs

* (feat) Add PowerOfAttorneyRequestExpiration model, factory, and specs

* (feat) Add PowerOfAttorneyRequestResolution model, factory, and specs

* (feat) Add PowerOfAttorneyForm model, factory, and specs

* (fix) Rename directory due to misspelling

* (fix) Add table name prefix override and ActiveRecord dependency for POA requests

- (feat) Override `table_name_prefix` to 'ar_' for models in the Accredited Representative Portal
- (feat) Add `activerecord` as a development dependency to fix spec issues

This ensures Power of Attorney request models in the engine use the correct table prefix
and that all specs pass successfully.

* (fix) Apply requested PR changes; all specs passing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants