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

# CertificateService

Orchestrates the full certificate-of-insurance lifecycle — retrieval, creation, editing, deletion, renewal, resend, and preview/imaging — by combining policy/limits/OSC data from `ICertificateInformationService`, authorization checks from `ICertificateSecurityService`, delivery-preference lookups from `ICertificatePreferenceService`, document generation from the `Document.IDocumentService`/`Documents.IDocumentService` pair, and distribution/imaging side effects from `ICertificateDistributionService`, all persisted through `IUnitOfWork` and validated through `IValidationService`. It also builds `CertData.CertificateHolder` records via the `Domain.Model.Policies.Certificates.CertificateHolder` domain type to add, expire, or supersede certificate holders as part of certificate mutations.

## Purpose
- Retrieves single certificates and policy-scoped certificate lists, resolving each certificate holder's most recent superseding holder in the chain.
- Adds, edits, deletes, and renews certificates, applying authorization checks, FluentValidation-style validation, and re-imaging/re-distribution as needed.
- Determines whether an edited certificate's holder/coverage/DBA data actually changed, to decide whether the certificate needs to be re-imaged and redistributed as new versus resent.
- Computes and persists batch-print (mail) distribution status for certificate holders and policyholders based on the policy's certificate delivery preference and whether the certificate is a renewal.
- Generates and previews certificate document images/PDFs, and supplies read views for editable certificates and standard "other coverage" text options.
- Processes certificate-holder add/expire/supersede workflows through the `Domain.Model.Policies.Certificates.CertificateHolder` domain object.

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

## Public members
| Member | Signature | Purpose |
| --- | --- | --- |
| ImageNotFound | `public const string ImageNotFound` | The fixed error message text used when a certificate's image cannot be located or generated. |
| ImageNotFoundError | `public string ImageNotFoundError { get; }` | Instance-accessible wrapper exposing the `ImageNotFound` constant's text. |
| CertificateService (constructor) | `public CertificateService(IUnitOfWork uow, IValidationService validationService, IUserProfileService userProfileService, ICertificateInformationService certificateInformationService, ICertificateSecurityService certificateSecurityService, CertDocument.IDocumentService documentService, UtilDocument.IDocumentService utilDocumentService, ICertificatePreferenceService certificatePreferenceService, ICertificateDistributionService certificateDistributionService)` | Wires the unit of work, validation, user-profile, information/security/preference/distribution services, and both document-service collaborators, and constructs an internal `CertificateInformationDataHelper` bound to the same unit of work. |
| GetCertificate | `public Certificate GetCertificate(long certificateId)` | Loads a certificate by ID, resolves its holder's most-recent superseding holder (unless it is a bid certificate), and maps it to the `Certificate` contract. |
| GetCertificates | `public IEnumerable<Certificate> GetCertificates(long policyNumber, DateTime policyPeriodEffectiveDate)` | Returns all non-bid certificates for the given policy and period, each with its holder-supersession chain resolved. |
| GetCertificatesReadyForBatchDistribution | `public IEnumerable<Certificate> GetCertificatesReadyForBatchDistribution()` | Returns all non-bid certificates whose certificate-holder or policyholder distribution status is "ready to print," with holder-supersession chains resolved. |
| AddCertificate | `public long AddCertificate(CertificateEdit certificateEdit, DistributionOptions distributionOptions)` | Validates authorization and the edit DTO, builds and persists a new certificate (defaulting the holder action to Add when no current holder ID is supplied), images and distributes it, commits the transaction, and returns the new certificate's ID; rolls back and rethrows on any exception. |
| EditCertificate | `public void EditCertificate(long id, CertificateEdit certificateEdit, DistributionOptions distributionOptions)` | Validates authorization and the edit DTO, determines whether the change requires re-imaging (new issue date/user, "New" distribution point) versus a resend, applies the edit, recomputes batch print status, processes the certificate-holder action, optionally re-images, distributes, and commits; rolls back and rethrows on any exception. |
| DidCertificateChange | `public bool DidCertificateChange(CertData.Certificate dataCertificate, CertificateEdit certificateEdit)` | Compares DBA, policy period, and certificate-holder identity/name/address/job-description/other-coverage/cancellation-notice fields between the stored certificate and the edit, returning `true` on the first detected difference. |
| DeleteCertificate | `public void DeleteCertificate(long certificateId)` | Validates edit/delete authorization for the certificate, deletes it, and commits the transaction; rolls back and rethrows on any exception. |
| RenewCertificate | `public long RenewCertificate(long certificateId, CertificateEdit certificateEdit, PeriodBase renewalPeriod, DistributionOptions distributionOptions)` | Validates the certificate can be renewed (not already renewed), flags the existing certificate as renewed, builds a new certificate for the renewal period marked as a renewal, images and distributes it, commits, and returns the new certificate's ID; rolls back and rethrows on any exception. |
| ResendCertificate | `public void ResendCertificate(long certificateId, DistributionOptions distributionOptions)` | Loads the certificate, streams its existing/preview image to the distribution service for resend, and resets the batch print status when mailing to the certificate holder is requested. |
| PreviewCertificate | `public Stream PreviewCertificate(long certificateId)` | Loads the certificate and returns a `Stream` of its rendered image, generating a fresh preview if no image has been produced yet, or throwing `CertificateServiceException` if no image can be obtained. |
| GetStandardOtherCoverageTexts | `public IEnumerable<StandardOtherCoverageText> GetStandardOtherCoverageTexts()` | Returns all configured standard "other coverage" text options. |
| GetEditableCertificates | `public IEnumerable<Certificate> GetEditableCertificates(long policyNumber)` | Returns the policy's non-bid certificates created on or after the security-service's modification cutoff, restricted to those the current user is authorized to edit and whose cancellation status matches the corresponding policy period's cancellation status. |
| ProcessCertificateHolderAction | `internal CertData.CertificateHolder ProcessCertificateHolderAction(CertificateEdit certificateEdit, out CertData.CertificateHolder expiredOrSupersededCertHolder)` | Dispatches on the edit's requested certificate-holder action (`NoUpdate`, `Add`, `Expire`, `Supersede`) to load, create, expire, or supersede a `Domain.Model.Policies.Certificates.CertificateHolder`, returning the resulting processed holder and, for `Expire`/`Supersede`, the expired or superseded holder record. |
| SetCertificateBatchPrintStatus | `public void SetCertificateBatchPrintStatus(CertData.Certificate certificate, DistributionOptions distributionOptions)` | Sets both distribution statuses to "do not print," then sets the certificate-holder status to "ready to print" if mailing to the holder is requested; unless the distribution point is a resend, also sets the policyholder status to "ready to print" based on the policy's certificate delivery preference (mail delivery, or renewal notification type of Copy/Digest for renewals). |

## Behavioral notes
- A static constructor registers a large set of AutoMapper mappings (`Certificate`↔`CertificateSecurityProperties`, data-to-contract `Certificate`, `TradingAs`, `EmployerLiabilityLimit`, `OtherStatesPolicy`, `OtherStatesPolicyPeriod`, `CertificateHolder`/`Address`, `StandardOtherCoverageText`) once per process, including a custom limits resolver that selects OSC limits by code (falling back to the standard OSC limit) for OSC certificates and maps standard limits otherwise.
- `AddCertificate`, `EditCertificate`, `DeleteCertificate`, and `RenewCertificate` each wrap their work in `unitOfWork.Begin()`/`unitOfWork.Commit()`, with a `catch` that calls `unitOfWork.Rollback()` and rethrows on any exception.
- `PreviewCertificate` throws `CertificateServiceException` with the `ImageNotFound` message when neither an existing image nor a freshly generated preview image is available.
- `GetCertificateDataById` catches `InvalidOperationException` from a `Single()` lookup and rethrows as `CertificateServiceException("Error: Certificate not found.")`.
- Authorization is enforced via `ICertificateSecurityService.CertificateCanBeAdded`/`CertificateCanBeEdited`, throwing `SaifValidationException` when the current user is not authorized to add, edit, or delete a certificate.
- `ValidateCertificateCanBeRenewed` throws `SaifValidationException` if the certificate has already been renewed (`HasBeenRenewed`).
- The class carries a `CA1506:AvoidExcessiveClassCoupling` suppression, reflecting its dependency on a large number of collaborating services.*
- `ProcessCertificateHolderAction` is `internal`, meaning it is only reachable from within the same assembly (e.g., by tests) rather than being part of the externally consumable public surface.*

## Constraints and usage notes
- Only `uow`, `validationService`, `userProfileService`, and `documentService` are null-checked in the constructor via `Enforce.ArgumentNotNull`; `certificateInformationService`, `certificateSecurityService`, `utilDocumentService`, `certificatePreferenceService`, and `certificateDistributionService` are not validated for null.*
- `RenewCertificate` and `AddCertificate`/`EditCertificate` depend on `certificateInformationService`/`dataHelper` lookups (policy periods, OSC policy/period, limits, DBA) succeeding via `Single()`, which throws if no matching record exists.*

> **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/Policies/Certificates/CertificateService.cs`
