Rental suite
Monthly rental operations for houses, flats, and bedsitters — separate from the hotel PMS (hospitality_accommodation). Appears in the sidebar as its own Rental suite workspace (not under Operations).
Full product scope (screening, leases, collections, portal, maintenance, comms): see RENTAL_SUITE_MASTER_SCOPE.md.
Module key
rental_management — enable on subscription tier features.
Permissions
| Gate | Purpose |
|---|---|
view-rental |
Hub, units, leases (read) |
manage-rental-setup |
Add rental units |
manage-rental-leases |
Create/end leases, post rent, record payments |
manage-rental-communications |
Templates, broadcasts, resend (Phase 6) |
manage-rental-screening |
Applications, screening, approve/deny (Phase 7) |
Data model (Phase 0 foundation)
| Table | Purpose |
|---|---|
rental_properties |
Building / estate per branch (auto-created default on first unit) |
rental_units |
Rentable unit; links to property |
rental_leases |
Tenancy: tenant (customers), unit, lifecycle status, billing day |
rent_invoices |
One row per calendar month; amounts + paid_amount; FIFO allocation |
rent_payments / rent_payment_allocations |
Payment mirror linked to invoices |
rental_settings |
Grace days, late fees, auto-post rent |
rental_deposits |
Security deposit ledger (optional on lease create) |
folios |
Tenant account (folio_type = rental) — charges & payments |
Typical workflow
- Rental units — add each house/flat; a default property is created for the branch if needed.
- New lease — pick vacant unit + CRM customer; optional deposit and “post first month rent”.
- Monthly rent — use Post this month rent on the lease, or enable auto post in settings and run
php artisan rental:post-monthly-rent(also scheduled daily). - Late fees — after grace period,
rental:apply-late-fees(scheduled) or manual apply via billing service. - When tenant pays — Record rent payment on the lease; oldest open invoices are paid first (FIFO).
- End lease when they move out — unit returns to vacant.
Artisan commands
| Command | Purpose |
|---|---|
rental:post-monthly-rent |
Post invoices for leases whose billing_day matches today (idempotent) |
rental:apply-late-fees |
Apply configured late fees to overdue open invoices |
rental:run-communication-automations |
Tenant rent due / overdue / renewal emails (per org settings) |
Routes
Prefix: /rental (tenant URL). Names: rental.*.
| Route | Screen |
|---|---|
rental.index |
Hub |
rental.rent-due |
Rent due — overdue & pending invoices (balance due) |
rental.units.index |
Units |
rental.leases.* |
Leases |
Phase 1 (collection)
| Route | Screen |
|---|---|
rental.rent-roll |
Rent roll — portfolio outstanding + aging per lease |
rental.payments.receipt |
PDF receipt for a rent payment |
rental.invoices.waive-late-fee |
Waive late fee (requires manage-rental-billing) |
rental.deposits.* |
Release, refund, or apply security deposit |
Rent due includes arrears aging filters (1–30, 31–60, 61–90, 90+ days overdue).
Phase 2 (lease management)
| Route / action | Purpose |
|---|---|
rental.renewals.index |
Leases ending in 60 / 30 / 7 days |
rental.leases.notice |
Record notice to vacate |
rental.leases.renew |
Create renewal draft |
rental.leases.activate-renewal |
Activate draft and end prior lease |
rental.leases.documents.* |
Generate PDF, download, sign (MVP), email tenant |
Scheduled: rental:lease-renewal-reminders (daily 08:00) logs staff reminders in rental_communication_logs.
Phase 3 (online pay)
Enable online pay in rental_settings.online_pay_enabled (per org).
| Route | Purpose |
|---|---|
rental.leases.pay-links.store |
Staff creates tenant pay link |
rent.pay.show |
Public M-Pesa checkout (token in URL) |
rent.pay.stk |
Initiate STK → PaymentIntent |
Webhooks (/webhooks/{slug}/mpesa/stk-callback) fulfill rent intents via RentCollectionService::applyGatewayPayment().
Env: RENTAL_MPESA_SIMULATE=true (default in local) skips live Daraja API.
Phase 4 (tenant portal)
Enable rental_settings.portal_enabled per organization.
| Route | Purpose |
|---|---|
rental.portal.login |
Phone OTP or email magic link |
rental.portal.dashboard |
Balance, pay rent, leases |
rental.portal.documents |
Download lease PDFs |
rental.portal.profile |
Contact + notification prefs |
rental.leases.portal-invite |
Staff sends invite + magic link |
Non-production OTP is always 123456.
Phase 5 (maintenance)
| Route | Purpose |
|---|---|
rental.maintenance.index |
Staff queue (filter by status) |
rental.maintenance.show |
Assign, update status, comments |
rental.units.maintenance.store |
Staff log request for a unit |
rental.portal.maintenance.* |
Tenant report & track issues |
When a request is In progress, the unit status becomes Maintenance and new leases are blocked until work is completed.
Phase 6 (communication hub)
| Route | Purpose |
|---|---|
rental.communications.index |
Inbox log (email, SMS, internal) |
rental.communications.templates |
View/edit message templates |
rental.communications.send |
Broadcast to all tenants in a property |
rental.communications.resend |
Resend a prior outbound message |
Scheduled: rental:run-communication-automations (daily 08:30). Tenant opt-out: customers.email_opt_out, customers.sms_opt_out. Env: RENTAL_SMS_SIMULATE.
Phase 7 (tenant screening)
| Route | Purpose |
|---|---|
rental.applications.index |
Application queue (filter by status) |
rental.applications.create |
Staff intake + generate public apply link |
rental.applications.show |
Review, order screening, approve/deny |
rental.applications.approve |
Creates draft lease + CRM customer |
rent.apply.show |
Public application form (/apply/rent/{token}) |
Screening provider: RENTAL_SCREENING_PROVIDER=simulated (default) or manual. Simulated completes instantly with a demo score; manual lets staff upload results.
Phase 8 (reports & polish)
| Route | Purpose |
|---|---|
rental.reports.index |
Reports catalog |
rental.rent-roll |
Rent roll (with CSV export) |
rental.reports.arrears |
Arrears aging by bucket |
rental.reports.occupancy |
Unit vacancy / occupancy |
rental.reports.deposits |
Security deposit register |
rental.reports.lease-expiry |
Leases ending within N days |
rental.reports.communications |
Message delivery summary |
The suite hub (rental.index) shows owner KPIs: occupancy %, collected this month, outstanding/overdue, deposits held, open maintenance and applications.
Each report has a matching …/export route returning UTF-8 CSV.
Settings & integrations
| Route | Purpose |
|---|---|
rental.settings.edit |
Billing, portal, online pay, comms automations |
rental:integrations-check |
CLI health check for M-Pesa / SMS env |
See INTEGRATIONS.md and OPERATIONS.md.
Tests
tests/Feature/Rental/RentalManagementPhase1Test.php — hub, end-to-end lease flow
tests/Feature/Rental/RentalSuitePhase0Test.php — property backfill, FIFO pay, late fees, idempotent post
tests/Feature/Rental/RentalSuitePhase1Test.php — prorate, waiver, receipt PDF, rent roll
tests/Feature/Rental/RentalSuitePhase2Test.php — lease PDF, notice, renewal draft, renewals dashboard
tests/Feature/Rental/RentalSuitePhase3Test.php — pay link, STK intent, webhook FIFO, partial pay
tests/Feature/Rental/RentalSuitePhase4Test.php — magic link, OTP login, documents, staff invite
tests/Feature/Rental/RentalSuitePhase5Test.php — tenant submit, unit maintenance, lease block, staff queue
tests/Feature/Rental/RentalSuitePhase6Test.php — templates, opt-out, rent-due automation, broadcast, inbox
tests/Feature/Rental/RentalSuitePhase7Test.php — public apply, screening, approve draft lease, deny
tests/Feature/Rental/RentalSuitePhase8Test.php — owner dashboard, reports hub, arrears, occupancy, CSV export, deposits
tests/Feature/Rental/RentalIntegrationsTest.php — settings UI, SMS/M-Pesa health, Daraja config
Related
- CRM
customers= tenants - Hotel PMS remains under
hospitality/accommodationfor nightly guests