Skip to main content
All Docs
FeaturesPurple PepperUpdated April 7, 2026

Rent Schedule Engine

Rent Schedule Engine

The rent schedule engine lets agents generate, preview, and manage rent payment schedules for tenancy terms. Schedules can be auto-calculated from term parameters or built manually entry by entry.

Overview

Each tenancy term can have a set of rent_schedule_payments — individual payment entries that together form the complete schedule. Each entry records:

  • Amount (in pence, integer)
  • Due date
  • Period start / end
  • Label (e.g. "Month 1", "Pro-rata (partial week)")
  • Type flags: isProRata, isCustom
  • Sort order for display
  • Notes for agent annotations

UI Panel

The <RentSchedulePanel> component is embedded on the tenancy term detail page. It exposes three tabs:

Schedule Tab

Displays all saved payment entries in a table with:

ColumnDescription
#Sort order
LabelEntry name and optional note
Due DateFormatted payment due date
AmountPayment amount (£)
Running TotalCumulative total at this row
TypeStandard, Pro-rata, or Custom badge
ActionsRemove individual entry

A summary bar at the top shows the overall total and payment count. A Clear All button removes the entire schedule after confirmation.

If payments do not sum correctly against the expected total, a discrepancy indicator is shown.

Generate Tab

Auto-computes a schedule from the tenancy term's parameters.

Configurable options:

  • Frequency: Monthly, Weekly, or Custom
  • Due day: Day of the month/week the payment falls on
  • Start date / End date: Override or inherit from the tenancy term

Preview before saving: The panel calls the preview procedure first so the agent can review the calculated entries before they are committed to the database. Generating a schedule replaces any existing one.

Custom Tab

Manually define individual payment entries.

  • Add entries with amount, due date, label, and optional notes.
  • Choose Replace mode to overwrite the existing schedule, or Append mode to add entries to it.

Calculation Logic

The generateRentSchedule() utility produces entries based on frequency:

Monthly

  1. Pro-rata first period — from the start date to the end of the first calendar month (if the start date is not the 1st).
  2. Full monthly entries — one entry per full calendar month.
  3. Pro-rata last period — from the start of the final partial month to the end date (if the end date is not the last day of the month).

Weekly

  • Weekly rent is derived from the monthly figure: monthlyRent × 12 ÷ 52.
  • Partial weeks at the start and end of the term are pro-rated.

Custom

  • Returns an empty schedule. The agent is expected to populate entries manually using the Custom tab.

All amounts are stored and calculated as pence (integers) to avoid floating-point rounding errors.

Validation

validateScheduleTotal() sums all entry amounts and compares the result to the expected total. A discrepancy of up to £1 is tolerated to account for rounding across pro-rata periods.


tRPC API Reference

All procedures live under the rentSchedule router.

rentSchedule.preview

Stateless calculation — returns computed entries without persisting.

const result = await trpc.rentSchedule.preview.query({
  tenancyTermId: string,
  frequency: "monthly" | "weekly" | "custom",
  startDate: string,   // ISO date
  endDate: string,     // ISO date
  monthlyRentPence: number,
  dueDay?: number,
});

rentSchedule.generate

Computes and persists a schedule, replacing any existing entries.

await trpc.rentSchedule.generate.mutate({
  tenancyTermId: string,
  frequency: "monthly" | "weekly" | "custom",
  startDate: string,
  endDate: string,
  monthlyRentPence: number,
  dueDay?: number,
});

rentSchedule.list

Fetches saved entries sorted by sortOrder, along with a running total and entry count.

const { entries, totalPence, entryCount } =
  await trpc.rentSchedule.list.query({ tenancyTermId: string });

rentSchedule.saveCustomEntries

Saves manually defined entries. Supports replace (overwrites) or append (adds to existing).

await trpc.rentSchedule.saveCustomEntries.mutate({
  tenancyTermId: string,
  mode: "replace" | "append",
  entries: Array<{
    label: string,
    amountPence: number,
    dueDate: string,
    periodStart?: string,
    periodEnd?: string,
    notes?: string,
  }>,
});

rentSchedule.deleteEntry

Removes a single payment entry by ID.

await trpc.rentSchedule.deleteEntry.mutate({ id: string });

rentSchedule.clearSchedule

Bulk-deletes all entries for a given tenancy term.

await trpc.rentSchedule.clearSchedule.mutate({ tenancyTermId: string });

rentSchedule.validate

Checks whether saved entries sum to the expected total (£1 tolerance).

const { isValid, discrepancyPence } =
  await trpc.rentSchedule.validate.query({
    tenancyTermId: string,
    expectedTotalPence: number,
  });

Audit Logging

All mutating procedures (generate, saveCustomEntries, deleteEntry, clearSchedule) emit audit log entries so changes to a rent schedule are fully traceable.