Skip to content

[contracts] allows reissue of contracts - #14593

Open
part-avocado wants to merge 5 commits into
hackclub:mainfrom
part-avocado:main
Open

[contracts] allows reissue of contracts#14593
part-avocado wants to merge 5 commits into
hackclub:mainfrom
part-avocado:main

Conversation

@part-avocado

Copy link
Copy Markdown

Summary of the problem

current implementation does not allow anybody to rescind/resend forms with incorrect information, and only allows admins to void current contract

Describe your changes

  • Contract#owned_by? (new) + Contract::PartyPolicy#resend? (broadened): the contract's own signee/organizer can now re-send an unchanged invite to another non-HCB party on their own contract, not just admins. The HCB party stays admin-only, and the self-service clause is a single line to drop if it ever needs to be restricted back to admins only.
  • Fixed Event::Application#check_cosigner_update to void with reissuing: true and link the new contract via reissue_of, matching the reissue chain used everywhere else (ContractsController#reissue, Payroll::Position), instead of leaving orphaned, unlinked voided contracts.
  • Added OrganizerPositionInvite#resend_to_cosigner (policy + controller action + route + UI modal on the invite's own show page), mirroring Event::Application's existing action — it previously had no self-service cosigner-fix path, only an admin-only send_contract.

external_service: manual contracts need no special-casing: per dev-docs/guides/contracts.md they're created directly via console already in the signed state, so they never have anything pending to resend as the existing void/archive guards already no-op safely for them.

Added specs (spec/policies/contract/party_policy_spec.rb, and additions to spec/models/contract_spec.rb and spec/controllers/organizer_position_invites_controller_spec.rb) modeled on existing patterns in the repo.

Closes #14545.

claude and others added 5 commits August 12, 2026 23:15
Generalizes the void+resend pattern that only existed for Event::Application
cosigners into a consistent, self-service-capable feature:

- Contract::PartyPolicy#resend? now allows the contract's own signee/organizer
  to re-send an unchanged invite to another non-HCB party (not just admins).
  The HCB party stays admin-only, and the self-service clause is a single
  line to drop if it needs to be restricted back to admins.
- Event::Application#check_cosigner_update now voids with reissuing: true and
  links the new contract via reissue_of, matching the reissue chain used
  everywhere else instead of leaving orphaned voided contracts.
- OrganizerPositionInvite gets the same "fix cosigner email and resend"
  action Event::Application already had (resend_to_cosigner), since it had
  no self-service path at all before - only an admin-only send_contract.

external_service: manual contracts need no special-casing here: they're
created directly in the signed state via console per
dev-docs/guides/contracts.md, so they never have anything pending to resend.

Addresses hackclub#14545.
send_contract reads event.airtable_record, which was hitting the real
Airtable API and failing all four new specs with
WebMock::NetConnectNotAllowedError.
mark_voided! calls archive_on_docuseal! (DELETE /submissions/:id), which
wasn't stubbed and made the "voids and reissues" spec hit
WebMock::NetConnectNotAllowedError.
…e-8bovsd

Let signing parties fix a wrong cosigner email and resend contracts

--- 
## Changes
- `Contract#owned_by?` (new) + `Contract::PartyPolicy#resend?` (broadened): the contract's own signee/organizer can now re-send an unchanged invite to another non-HCB party on their own contract, not just admins. The HCB party stays admin-only, and the self-service clause is a single line to drop if it ever needs to be restricted back to admins only.
- Fixed `Event::Application#check_cosigner_update` to void with `reissuing: true` and link the new contract via `reissue_of`, matching the reissue chain used everywhere else (`ContractsController#reissue`, `Payroll::Position`), instead of leaving orphaned, unlinked voided contracts.
- Added `OrganizerPositionInvite#resend_to_cosigner` (policy + controller action + route + UI modal on the invite's own show page), mirroring `Event::Application`'s existing action — it previously had no self-service cosigner-fix path, only an admin-only `send_contract`.

`external_service: manual` contracts need no special-casing: per `dev-docs/guides/contracts.md` they're created directly via console already in the `signed` state, so they never have anything pending to resend — the existing void/archive guards already no-op safely for them.

Added specs (`spec/policies/contract/party_policy_spec.rb`, and additions to `spec/models/contract_spec.rb` and `spec/controllers/organizer_position_invites_controller_spec.rb`) modeled on existing patterns in the repo. I wasn't able to run the suite locally in my environment, so I'm relying on this PR's CI run to confirm they pass.

Closes hackclub#14545.
@part-avocado
part-avocado requested review from a team and a lite review from Copilot August 12, 2026 23:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@part-avocado part-avocado changed the title allows reissue of contracts [contracts] allows reissue of contracts Aug 12, 2026
@part-avocado
part-avocado requested a lite review from Copilot August 14, 2026 15:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Contracts] Resend contract

3 participants