---
title: SubpoenaSaveService
summary: API reference for SubpoenaSaveService.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-24
library: SAIF.Services
reference_type: package
---

# SubpoenaSaveService

Owns the create/update/approve/disapprove/delete lifecycle for a subpoena and its recipients, translating between the contract `Subpoena` model and the `SAIF.Data.Model.Legal.Subpoenas.Subpoena` entity graph. It checks the requesting employee's initiate/approve authority limits via `IBillServiceHelper.UserAuthorityLevel` before auto-approving a subpoena, computes issue dates via `IBillServiceHelper.GetNextIssueDate`/`IWorkCalendarService.NextWorkDay`, and validates the incoming model with `IValidationService` before any persistence occurs.

## Purpose
- Approves a subpoena automatically when the requesting employee's initiate or approve authority limit covers the highest recipient paid amount, then saves it.
- Reverts a subpoena to in-progress status and saves it (disapproval).
- Deletes a subpoena outright when found.
- Validates and persists a subpoena (new or existing), including optimistic-concurrency checking via `UpdateNumber`, opposing-counsel address validation, recipient synchronization (add/update/remove, including witness legal-person and address upsert), and issue-date computation — all inside a single transaction.

## Context
- Namespace: `SAIF.Services.Legal.Subpoenas`
- Assembly/package: `SAIF.Services` (packaged inside the `SAIF.SAIFCode.Core` NuGet package).

## Public members
| Member | Signature | Purpose |
| --- | --- | --- |
| SubpoenaSaveService (constructor) | `public SubpoenaSaveService(IUnitOfWork unitOfWork, IUserProfileService userProfileService, IValidationService validationService, IBillServiceHelper billServiceHelper, IWorkCalendarService workCalendarService)` | Wires the unit of work, current-user profile (captured as an uppercased static `_currentUser`), the validation service, the authority-limit/issue-date helper, and the work-calendar service; null-checks all five collaborators. |
| ApproveSubpoena | `public long ApproveSubpoena(Subpoena subpoena, IMessageContainer messageContainer)` | Defaults the subpoena to in-progress status if unset, then — if the current employee's initiate or approve authority limit is at least the highest recipient `PaidAmount` — marks it approved, sets `ApprovedByEmployeeId`/`ApprovedDate` to the current employee/today, and delegates to `SaveSubpoena` to validate and persist; otherwise saves it unapproved. Returns the persisted subpoena's ID, or `0` on validation failure. |
| DisapproveSubpoena | `public bool DisapproveSubpoena(Subpoena subpoena, IMessageContainer messageContainer)` | Sets the subpoena's status to in-progress and saves it via `SaveSubpoena`, returning `true` only if the save produced a nonzero ID. |
| DeleteSubpoena | `public bool DeleteSubpoena(long subpoenaId, IMessageContainer messageContainer)` | Looks up the subpoena by ID and, if found, deletes it inside a transaction and returns `true`; returns `false` if no matching subpoena exists. |
| SaveSubpoena | `public long SaveSubpoena(Subpoena subpoena, IMessageContainer messageContainer)` | Defaults status (in-progress) and type (medical records) when unset, validates the subpoena (unless already paid) via `ValidateSubpoena`/`IValidationService` — returning `0` and adding errors to `messageContainer` on failure — then within a transaction: rejects with an optimistic-concurrency error if `UpdateNumber` is stale, rejects if the linked legal case's opposing-counsel firm has no address, copies all subpoena fields onto the data entity (computing issue date via `IBillServiceHelper`/`IWorkCalendarService` for approvals and witness types), synchronizes recipients (add/update/remove, including legal-person and address upsert for witness recipients), adds the entity if new, commits, and returns its ID. |

## Behavioral notes
- `ApproveSubpoena`'s auto-approval decision compares the recipient's *maximum* `PaidAmount` against the current employee's initiate and approve authority limits (`IBillServiceHelper.UserAuthorityLevel`); if neither limit covers it, the subpoena is saved without approval.
- `SaveSubpoena` skips its own `ValidateSubpoena` call entirely when the subpoena's current status is `PaidCode`, allowing paid subpoenas to be re-saved (e.g., recipient corrections) without full re-validation.*
- Recipient synchronization (`SaveRecipients`) removes data recipients no longer present in the incoming model, then for each incoming recipient short-circuits (`continue`) unless it is new or `HasRecipientChanged` detects a material difference, avoiding unnecessary update-user/date stamping.
- Witness recipients' `LegalPerson`/`LegalPersonAddress` records are created via `CreateNewLegalPerson` for brand-new recipients or people, and updated in place via `UpdateLegalPerson` otherwise; provider-type recipients instead resolve `ProviderLocation`/`RegisteredAgentLocation` by ID.
- Issue date defaults to `IBillServiceHelper.GetNextIssueDate("LS")` for every new/updated subpoena, but is recomputed (and pushed forward two work days via `IWorkCalendarService.NextWorkDay` for witness-type subpoenas) whenever the status transitions to approved.
- `_currentUser` is a `static` field assigned from the constructor's injected `IUserProfileService`, so it reflects whichever instance was constructed most recently within the process rather than being strictly per-instance state.*

## Constraints and usage notes
- `ApproveSubpoena`, `DisapproveSubpoena`, `DeleteSubpoena`, and `SaveSubpoena` all throw via `Enforce.ArgumentNotNull` if `messageContainer` is `null`; `ApproveSubpoena` and `SaveSubpoena` additionally throw if `subpoena` is `null`. `DisapproveSubpoena` carries a `CA1062` suppression acknowledging it does not null-check `subpoena` itself.
- `SpecialDeliveryText` is truncated to at most 1000 characters before being stored.
- `SaveSubpoena` rolls back (without committing) and returns `0` both on stale `UpdateNumber` and on a missing opposing-counsel address, leaving the caller to surface the added `messageContainer` errors.

> **Note:** Statements marked with * were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with ** could not be confirmed; treat as unknown until verified.

## Sources
- `Services/SAIF.Services/Legal/Subpoenas/SubpoenaSaveService.cs`
