Phase 2 tweaks: admin tenant creation, unit delete, frequency, UI overhaul
- Admin panel: create tenants with org + first user, manage org status (active/suspended/archived), contract number and plan level fields - Units: delete with invoice check, assessment group dropdown binding - Assessment groups: frequency field (monthly/quarterly/annual) with income calculations normalized to monthly equivalents - Sidebar: grouped nav sections (Financials, Assessments, Transactions, Planning, Reports, Admin), renamed Chart of Accounts to Accounts - Header: replaced text with SVG logo - Capital projects: Kanban as default view, table-only PDF export, Future category (beyond 5-year plan) - Auth: block login for suspended/archived organizations Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,12 +6,28 @@ export class AssessmentGroupsService {
|
||||
constructor(private tenant: TenantService) {}
|
||||
|
||||
async findAll() {
|
||||
// Normalize all income calculations to monthly equivalent
|
||||
// monthly: amount * units (already monthly)
|
||||
// quarterly: amount/3 * units (convert to monthly)
|
||||
// annual: amount/12 * units (convert to monthly)
|
||||
return this.tenant.query(`
|
||||
SELECT ag.*,
|
||||
(SELECT COUNT(*) FROM units u WHERE u.assessment_group_id = ag.id) as actual_unit_count,
|
||||
ag.regular_assessment * ag.unit_count as monthly_operating_income,
|
||||
ag.special_assessment * ag.unit_count as monthly_reserve_income,
|
||||
(ag.regular_assessment + ag.special_assessment) * ag.unit_count as total_monthly_income
|
||||
CASE ag.frequency
|
||||
WHEN 'quarterly' THEN ag.regular_assessment / 3
|
||||
WHEN 'annual' THEN ag.regular_assessment / 12
|
||||
ELSE ag.regular_assessment
|
||||
END * ag.unit_count as monthly_operating_income,
|
||||
CASE ag.frequency
|
||||
WHEN 'quarterly' THEN ag.special_assessment / 3
|
||||
WHEN 'annual' THEN ag.special_assessment / 12
|
||||
ELSE ag.special_assessment
|
||||
END * ag.unit_count as monthly_reserve_income,
|
||||
(CASE ag.frequency
|
||||
WHEN 'quarterly' THEN (ag.regular_assessment + ag.special_assessment) / 3
|
||||
WHEN 'annual' THEN (ag.regular_assessment + ag.special_assessment) / 12
|
||||
ELSE ag.regular_assessment + ag.special_assessment
|
||||
END) * ag.unit_count as total_monthly_income
|
||||
FROM assessment_groups ag
|
||||
ORDER BY ag.name
|
||||
`);
|
||||
@@ -25,9 +41,9 @@ export class AssessmentGroupsService {
|
||||
|
||||
async create(dto: any) {
|
||||
const rows = await this.tenant.query(
|
||||
`INSERT INTO assessment_groups (name, description, regular_assessment, special_assessment, unit_count)
|
||||
VALUES ($1, $2, $3, $4, $5) RETURNING *`,
|
||||
[dto.name, dto.description || null, dto.regularAssessment || 0, dto.specialAssessment || 0, dto.unitCount || 0],
|
||||
`INSERT INTO assessment_groups (name, description, regular_assessment, special_assessment, unit_count, frequency)
|
||||
VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`,
|
||||
[dto.name, dto.description || null, dto.regularAssessment || 0, dto.specialAssessment || 0, dto.unitCount || 0, dto.frequency || 'monthly'],
|
||||
);
|
||||
return rows[0];
|
||||
}
|
||||
@@ -44,6 +60,7 @@ export class AssessmentGroupsService {
|
||||
if (dto.specialAssessment !== undefined) { sets.push(`special_assessment = $${idx++}`); params.push(dto.specialAssessment); }
|
||||
if (dto.unitCount !== undefined) { sets.push(`unit_count = $${idx++}`); params.push(dto.unitCount); }
|
||||
if (dto.isActive !== undefined) { sets.push(`is_active = $${idx++}`); params.push(dto.isActive); }
|
||||
if (dto.frequency !== undefined) { sets.push(`frequency = $${idx++}`); params.push(dto.frequency); }
|
||||
|
||||
if (!sets.length) return this.findOne(id);
|
||||
|
||||
@@ -61,9 +78,27 @@ export class AssessmentGroupsService {
|
||||
const rows = await this.tenant.query(`
|
||||
SELECT
|
||||
COUNT(*) as group_count,
|
||||
COALESCE(SUM(regular_assessment * unit_count), 0) as total_monthly_operating,
|
||||
COALESCE(SUM(special_assessment * unit_count), 0) as total_monthly_reserve,
|
||||
COALESCE(SUM((regular_assessment + special_assessment) * unit_count), 0) as total_monthly_income,
|
||||
COALESCE(SUM(
|
||||
CASE frequency
|
||||
WHEN 'quarterly' THEN regular_assessment / 3
|
||||
WHEN 'annual' THEN regular_assessment / 12
|
||||
ELSE regular_assessment
|
||||
END * unit_count
|
||||
), 0) as total_monthly_operating,
|
||||
COALESCE(SUM(
|
||||
CASE frequency
|
||||
WHEN 'quarterly' THEN special_assessment / 3
|
||||
WHEN 'annual' THEN special_assessment / 12
|
||||
ELSE special_assessment
|
||||
END * unit_count
|
||||
), 0) as total_monthly_reserve,
|
||||
COALESCE(SUM(
|
||||
CASE frequency
|
||||
WHEN 'quarterly' THEN (regular_assessment + special_assessment) / 3
|
||||
WHEN 'annual' THEN (regular_assessment + special_assessment) / 12
|
||||
ELSE regular_assessment + special_assessment
|
||||
END * unit_count
|
||||
), 0) as total_monthly_income,
|
||||
COALESCE(SUM(unit_count), 0) as total_units
|
||||
FROM assessment_groups WHERE is_active = true
|
||||
`);
|
||||
|
||||
Reference in New Issue
Block a user