---
title: Renewal Quote
summary: Lets underwriting staff review a policy's renewal premium by class code, adjust the quote lines, and issue the renewal offer to the employer.
status: draft
owner: Policy Renewals Team
last_reviewed: 2026-09-09
---

# Renewal Quote

Renewal Quote is the main working screen of the Policy Renewals application.
Underwriting staff open it from the Renewal Queue for a policy that is
approaching expiration and use it to review the quote the rating library has
produced: the premium for each class code, the experience modifier, and the
renewal effective date. The user can adjust individual premium lines, give a
reason for the adjustment, save the quote, and issue the renewal offer to the
employer. The action loads the quote for the `policyNumber` route value and
returns a state view when none can be produced. From here the user returns to
the queue, opens the quote history, or moves to the policy summary in the
Policy Services Portal.

## Route

| Controller | Action | Verb | URL | Parameters | View | Layout |
| --- | --- | --- | --- | --- | --- | --- |
| `RenewalController` | `Quote` | GET | `/Renewal/Quote/{policyNumber}` | `policyNumber` | `Views/Renewal/Quote.cshtml` | `_Layout` |
| `RenewalController` | `Quote` | POST | `/Renewal/Quote/{policyNumber}` | `policyNumber`, `RenewalQuoteViewModel` | `Views/Renewal/Quote.cshtml` (redisplayed when validation fails) | `_Layout` |

## Access

| Requirement | Declared on | Effect |
| --- | --- | --- |
| `[SaifAuthorize(Roles = "Renewals.Read,Renewals.Underwriting")]` | `BaseController` | Only users holding one of the two roles can open any action of a controller that derives from `BaseController` |
| `[SaifAuthorize(Roles = "Renewals.Underwriting")]` | `RenewalController.IssueOffer` | Only underwriting staff can issue a renewal offer |
| `CanUserUpdate()` | `RenewalController.Quote` | Returns `true` only for users in `Renewals.Underwriting`; when `false`, `IsReadOnly` is set, the grid shows no edit commands, and **Save quote** and **Issue offer** are hidden |

## Entry conditions
- The user selects a policy in the Renewal Queue and follows the **Open quote**
  link, which passes `policyNumber` in the route.
- The user opens a bookmarked or emailed URL of the form
  `/Renewal/Quote/{policyNumber}`.
- The default route `Home/Index` redirects to the Renewal Queue, so the quote
  screen is never the application start page.
- The action requires a policy number from the route or from `WebContext`. When
  neither supplies one, it returns the `InvalidContext` state view.

## Fields

| Field | Binds to | Control | Purpose | Validation |
| --- | --- | --- | --- | --- |
| Policy number | `RenewalQuoteViewModel.PolicyNumber` | `Html.DisplayFor` | Identifies the policy being renewed | None; display only |
| Employer | `RenewalQuoteViewModel.EmployerName` | `Html.DisplayFor` | Insured employer of record | None; display only |
| Renewal effective date | `RenewalQuoteViewModel.EffectiveDate` | Kendo DatePicker (`Html.Kendo().DatePickerFor`) | Start of the renewal term | `[Required]` and `[Remote("ValidateEffectiveDate", "Renewal")]`; client-side yes |
| Experience modifier | `RenewalQuoteViewModel.ExperienceModifier` | Kendo NumericTextBox (`Html.Kendo().NumericTextBoxFor`) | Modifier applied to the manual premium | `[Range(0.50, 2.50)]`; client-side yes |
| Quote lines | `RenewalQuoteViewModel.QuoteLines` | Kendo Grid (`Html.Kendo().Grid<QuoteLineViewModel>()`) | Calculated and adjusted premium for each class code | `QuoteLineViewModelValidator` requires a non-negative adjusted premium; client-side no |
| Adjustment reason | `RenewalQuoteViewModel.AdjustmentReason` | `Html.TextAreaFor` | Explains why any line differs from the calculated premium | `[StringLength(500)]`; required by `RenewalQuoteViewModelValidator` when a reduction exceeds 25 percent; client-side no |
| Total premium | `RenewalQuoteViewModel.TotalPremium` | `Html.DisplayFor`, formatted as currency | Sum of the adjusted line premiums | None; display only |
| Save quote | None | `<button type="submit">` `btnSaveQuote` | Posts the adjusted quote | Hidden when `IsReadOnly` |
| Issue offer | None | `<button type="submit">` `btnIssueOffer`, in a form that posts to `IssueOffer` | Issues the renewal offer for the saved quote | Hidden when `IsReadOnly` |

## Operations

| Operation | Trigger | Request | Description | Delegates to |
| --- | --- | --- | --- | --- |
| load-quote | Page load | `GET Renewal/Quote` | Reads the renewal quote for the policy number and populates the header fields and the quote lines grid | `GetRenewalQuote` in `SAIF.Policy.Services`† |
| save-quote | `btnSaveQuote` click | `POST Renewal/Quote` | Re-rates the adjusted quote lines and saves the quote, then redisplays the screen with the new total | RecalculateRenewalPremium |
| issue-offer | `btnIssueOffer` click | `POST Renewal/IssueOffer` | Issues the renewal offer to the employer and redirects to the Renewal Queue | Renewal offer issuance |
| open-quote-help | `lnkQuoteHelp` click | `GET Renewal/QuoteHelp` | Returns the quote help partial | — |

## Dialogs and partials

| Name | Opens as | Returned by | Purpose |
| --- | --- | --- | --- |
| `_QuoteHelp` | kendoWindow, content loaded from the action URL | `GET Renewal/QuoteHelp` | Explains each premium line type and the limits on adjusting a line |

## AJAX and grid actions

| Request | Kind | Called by | Returns |
| --- | --- | --- | --- |
| `POST Renewal/QuoteLines_Read` | grid read | `quoteLinesGrid` data source | `DataSourceResult` of `QuoteLineViewModel` |
| `POST Renewal/QuoteLines_Update` | grid update | `quoteLinesGrid` inline edit | `DataSourceResult` with the updated line, or model state errors |
| `GET Renewal/ValidateEffectiveDate` | remote validator | `EffectiveDate` field | JSON `true`, or an error message string |

## Client-side behavior
- **Script module:** `Scripts/app/renewal/quote.js`
- `quoteLinesGrid` is a Kendo Grid with inline editing; after each
  `QuoteLines_Update` response the `quoteViewModel` `kendo.observable` view model
  recomputes `totalPremium`.
- The `EffectiveDate` DatePicker uses the policy expiration date as its minimum
  and relies on jQuery unobtrusive validation for the remote check.
- `lnkQuoteHelp` opens `_QuoteHelp` in a kendoWindow.
- Failed grid requests raise a toastr notification.

## States

| State view | Condition |
| --- | --- |
| `NoQuote` | `GetRenewalQuote` returns no quote because the policy is outside its renewal window |
| `InvalidContext` | No policy number can be resolved from the route or `WebContext` |

## Business rules

| Rule ID | Rule | Enforcement | Source |
| --- | --- | --- | --- |
| BR-SCR-001 | The renewal effective date must be the day after the current policy expiration date | `ValidateEffectiveDate` remote validator and `RenewalQuoteViewModelValidator` | `src/SAIF.Policy.Renewals.Web/Controllers/RenewalController.cs:131` |
| BR-SCR-002 | A quote line cannot be reduced by more than 25 percent of its calculated premium without an adjustment reason | `RenewalQuoteViewModelValidator` | `src/SAIF.Policy.Renewals.Web/Validators/RenewalQuoteViewModelValidator.cs:22` |
| BR-SCR-003 | Only underwriting staff can issue a renewal offer | `[SaifAuthorize]` on `IssueOffer` | `src/SAIF.Policy.Renewals.Web/Controllers/RenewalController.cs:98` |
| BR-APP-002 | A renewal quote is available only for a policy inside its renewal window | `NoQuote` state view returned by `Quote` | `src/SAIF.Policy.Renewals.Web/Controllers/RenewalController.cs:58` |

## Navigation

| Target | Trigger | Parameters |
| --- | --- | --- |
| Renewal Queue | **Back to queue** link; redirect after **Issue offer** | None |
| Quote History | **History** link | `policyNumber` route parameter |
| Policy Summary in the Policy Services Portal | **Policy summary** link | `policyNumber` carried in the web context; the portal URL is held in the `PolicyPortalUrl` app setting |

## Screen flow diagram

```mermaid
flowchart TD
    A[Renewal Quote] -->|Back to queue or Issue offer| B[Renewal Queue]
    A -->|History| C[Quote History]
    A -->|Policy summary| D[Policy Summary in the Policy Services Portal]
    B -->|Open quote| A
```

---

> [!NOTE]
> Statements marked with `*` are inferred from code patterns. Statements marked with `**` could not be verified from available source. Statements marked with `†` are sourced from package documentation retrieved with the Legends CLI.

## Sources
- src/SAIF.Policy.Renewals.Web/Controllers/BaseController.cs
- src/SAIF.Policy.Renewals.Web/Controllers/RenewalController.cs
- src/SAIF.Policy.Renewals.Web/Views/Renewal/Quote.cshtml
- src/SAIF.Policy.Renewals.Web/Views/Renewal/_QuoteHelp.cshtml
- src/SAIF.Policy.Renewals.Web/Models/RenewalQuoteViewModel.cs
- src/SAIF.Policy.Renewals.Web/Models/QuoteLineViewModel.cs
- src/SAIF.Policy.Renewals.Web/Validators/RenewalQuoteViewModelValidator.cs
- src/SAIF.Policy.Renewals.Web/Scripts/app/renewal/quote.js
