262 lines
6.2 KiB
TypeScript
262 lines
6.2 KiB
TypeScript
// services/leaseService.ts
|
|
// Handle lease management, creation, updates, and tenant relationships
|
|
|
|
import { and, eq } from "drizzle-orm";
|
|
import { db } from "../db/db.ts";
|
|
import { leases } from "../db/schema.ts";
|
|
import { Lease } from "../db/interfaces.ts";
|
|
import {
|
|
getE2ELeaseById,
|
|
getE2ELeasesByOwner,
|
|
getE2ELeasesByTenant,
|
|
isE2EEnabled,
|
|
} from "./e2eFixtures.ts";
|
|
|
|
// export interface Lease {
|
|
// id: string;
|
|
// title: string | null;
|
|
// property_id: string;
|
|
// property_address: string;
|
|
// tenant_id: string | null;
|
|
// owner_id: string;
|
|
// start_date: number;
|
|
// end_date: number;
|
|
// rent: number | null;
|
|
// security_deposit: number | null;
|
|
// lease_status: string | null; // 'draft', 'active', 'expired', 'terminated'
|
|
// lease_document_url: string | null;
|
|
// payment_schedule_id: string | null;
|
|
// late_fee_rules: string | null; // JSON string of late fee rules
|
|
// auto_renewal: boolean | null;
|
|
// encrypted_data: string | null;
|
|
// created_on: number;
|
|
// updated_on: number;
|
|
// }
|
|
|
|
// Create new lease
|
|
export async function createLease(
|
|
title: string,
|
|
property_id: string,
|
|
owner_id: string,
|
|
start_date: number,
|
|
end_date: number,
|
|
rent: number,
|
|
security_deposit: number = 0,
|
|
tenant_id?: string,
|
|
payment_schedule_id?: string,
|
|
) {
|
|
const now = Date.now();
|
|
return await db.insert(leases)
|
|
.values({
|
|
id: crypto.randomUUID(),
|
|
title,
|
|
property_id,
|
|
tenant_id: tenant_id || null,
|
|
owner_id,
|
|
start_date,
|
|
end_date,
|
|
rent,
|
|
security_deposit,
|
|
lease_status: "new",
|
|
lease_document_url: null,
|
|
payment_schedule_id: payment_schedule_id || null,
|
|
late_fee_rules: null,
|
|
auto_renewal: false,
|
|
encrypted_data: null,
|
|
created_on: now,
|
|
updated_on: now,
|
|
})
|
|
.returning();
|
|
}
|
|
|
|
// Get leases by property
|
|
export async function getLeasesByProperty(property_id: string) {
|
|
return await db.select()
|
|
.from(leases)
|
|
.where(eq(leases.property_id, property_id))
|
|
.orderBy(leases.created_on);
|
|
}
|
|
|
|
// Get leases by owner (landlord)
|
|
export async function getLeasesByOwner(owner_id: string) {
|
|
if (isE2EEnabled()) {
|
|
return getE2ELeasesByOwner(owner_id);
|
|
}
|
|
return await db.select()
|
|
.from(leases)
|
|
.where(eq(leases.owner_id, owner_id))
|
|
.orderBy(leases.created_on);
|
|
}
|
|
|
|
// Get leases by tenant
|
|
export async function getLeasesByTenant(tenant_id: string) {
|
|
if (isE2EEnabled()) {
|
|
return getE2ELeasesByTenant(tenant_id);
|
|
}
|
|
return await db.select()
|
|
.from(leases)
|
|
.where(eq(leases.tenant_id, tenant_id))
|
|
.orderBy(leases.created_on);
|
|
}
|
|
|
|
// Get active leases by owner
|
|
export async function getActiveLeasesByOwner(owner_id: string) {
|
|
return await db.select()
|
|
.from(leases)
|
|
.where(and(
|
|
eq(leases.owner_id, owner_id),
|
|
eq(leases.lease_status, "active"),
|
|
))
|
|
.orderBy(leases.created_on);
|
|
}
|
|
|
|
// Get current lease for a property
|
|
export async function getCurrentLeaseForProperty(property_id: string) {
|
|
const result = await db.select()
|
|
.from(leases)
|
|
.where(and(
|
|
eq(leases.property_id, property_id),
|
|
eq(leases.lease_status, "active"),
|
|
));
|
|
return result[0] || null;
|
|
}
|
|
|
|
// Get lease by ID
|
|
export async function getLeaseById(id: string) {
|
|
if (isE2EEnabled()) {
|
|
return getE2ELeaseById(id);
|
|
}
|
|
const result = await db.select()
|
|
.from(leases)
|
|
.where(eq(leases.id, id));
|
|
return result[0] || null;
|
|
}
|
|
|
|
// Update lease
|
|
export async function updateLease(
|
|
id: string,
|
|
updates: Partial<Omit<Lease, "id" | "created_on">>,
|
|
) {
|
|
const now = Date.now();
|
|
return await db.update(leases)
|
|
.set({ ...updates, updated_on: now })
|
|
.where(eq(leases.id, id))
|
|
.returning();
|
|
}
|
|
|
|
// Assign tenant to lease
|
|
export async function assignTenantToLease(lease_id: string, tenant_id: string) {
|
|
const now = Date.now();
|
|
return await db.update(leases)
|
|
.set({
|
|
tenant_id,
|
|
lease_status: "active",
|
|
updated_on: now,
|
|
})
|
|
.where(eq(leases.id, lease_id))
|
|
.returning();
|
|
}
|
|
|
|
// Update lease status
|
|
export async function updateLeaseStatus(
|
|
id: string,
|
|
status: "draft" | "active" | "expired" | "terminated",
|
|
) {
|
|
const now = Date.now();
|
|
return await db.update(leases)
|
|
.set({
|
|
lease_status: status,
|
|
updated_on: now,
|
|
})
|
|
.where(eq(leases.id, id))
|
|
.returning();
|
|
}
|
|
|
|
// Set lease document URL
|
|
export async function setLeaseDocument(lease_id: string, document_url: string) {
|
|
const now = Date.now();
|
|
return await db.update(leases)
|
|
.set({
|
|
lease_document_url: document_url,
|
|
updated_on: now,
|
|
})
|
|
.where(eq(leases.id, lease_id))
|
|
.returning();
|
|
}
|
|
|
|
// Set payment schedule
|
|
export async function setPaymentSchedule(
|
|
lease_id: string,
|
|
payment_schedule_id: string,
|
|
) {
|
|
const now = Date.now();
|
|
return await db.update(leases)
|
|
.set({
|
|
payment_schedule_id,
|
|
updated_on: now,
|
|
})
|
|
.where(eq(leases.id, lease_id))
|
|
.returning();
|
|
}
|
|
|
|
// Set late fee rules
|
|
export async function setLateFeeRules(
|
|
lease_id: string,
|
|
late_fee_rules: object,
|
|
) {
|
|
const now = Date.now();
|
|
return await db.update(leases)
|
|
.set({
|
|
late_fee_rules: JSON.stringify(late_fee_rules),
|
|
updated_on: now,
|
|
})
|
|
.where(eq(leases.id, lease_id))
|
|
.returning();
|
|
}
|
|
|
|
// Enable/disable auto renewal
|
|
export async function setAutoRenewal(lease_id: string, auto_renewal: boolean) {
|
|
const now = Date.now();
|
|
return await db.update(leases)
|
|
.set({
|
|
auto_renewal,
|
|
updated_on: now,
|
|
})
|
|
.where(eq(leases.id, lease_id))
|
|
.returning();
|
|
}
|
|
|
|
// Delete lease
|
|
export async function deleteLease(id: string) {
|
|
return await db.delete(leases)
|
|
.where(eq(leases.id, id))
|
|
.returning();
|
|
}
|
|
|
|
// Get lease statistics for an owner
|
|
export async function getLeaseStatsByOwner(owner_id: string) {
|
|
const allLeases = await getLeasesByOwner(owner_id);
|
|
|
|
return {
|
|
total: allLeases.length,
|
|
draft: allLeases.filter((l) => l.lease_status === "draft").length,
|
|
active: allLeases.filter((l) => l.lease_status === "active").length,
|
|
expired: allLeases.filter((l) => l.lease_status === "expired").length,
|
|
terminated: allLeases.filter((l) => l.lease_status === "terminated").length,
|
|
with_tenant: allLeases.filter((l) => l.tenant_id !== null).length,
|
|
without_tenant: allLeases.filter((l) => l.tenant_id === null).length,
|
|
};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|