| 6 | | === 1. Извештај за вкупни приходи на изнајмувачите на недвижности за нивните изнајмени единици како и просечен приход остварен по изнајмена единица во тековната година. |
| 7 | | {{{ |
| 8 | | SELECT |
| 9 | | u.first_name, |
| 10 | | u.last_name, |
| 11 | | u.email, |
| 12 | | u.rating, |
| 13 | | lp.is_agent, |
| 14 | | COUNT(DISTINCT l.id) AS lease_count, |
| 15 | | COUNT(DISTINCT l.tenant_id) AS tenant_count, |
| 16 | | COALESCE(SUM(p.amount), 0) AS total_revenue, |
| 17 | | ROUND( |
| 18 | | CASE WHEN COUNT(DISTINCT l.id) > 0 |
| 19 | | THEN COALESCE(SUM(p.amount), 0) / COUNT(DISTINCT l.id) |
| 20 | | ELSE 0 |
| 21 | | END, 2 |
| 22 | | ) AS avg_revenue_per_lease |
| 23 | | FROM LandlordProfile lp |
| 24 | | JOIN UserD u ON u.id = lp.id |
| 25 | | JOIN Lease l ON lp.id = l.landlord_id |
| 26 | | LEFT JOIN Payment p |
| 27 | | ON p.lease_id = l.id |
| 28 | | AND p.payment_date >= date_trunc('year', CURRENT_DATE) |
| 29 | | GROUP BY u.id, u.first_name, u.last_name, u.email, u.rating, lp.is_agent |
| 30 | | ORDER BY total_revenue DESC; |
| 31 | | }}} |
| 32 | | |
| 33 | | |
| 34 | | === 2. Извештај за перформансите на недвижностите по градови: број на имоти, број на издавачки единици, активни единици, остварени приходи за тековната година по град како и просечна кирија по изнајмувачка единица како и остварен приход по објект. |
| 35 | | |
| 36 | | {{{ |
| 37 | | SELECT |
| 38 | | a.city, |
| 39 | | COUNT(DISTINCT p.id) as total_properties, |
| 40 | | COUNT(DISTINCT u.id) as total_units, |
| 41 | | COUNT(DISTINCT l.id) as active_leases, |
| 42 | | SUM(pay.amount) as total_revenue, |
| 43 | | ROUND(AVG(l.rent_amount),2) as avg_rent_per_lease, |
| 44 | | ROUND (SUM(pay.amount) / COUNT(DISTINCT p.id),2) as revenue_per_property |
| 45 | | FROM Address a |
| 46 | | JOIN Property p ON a.id = p.address_id |
| 47 | | JOIN Unit u ON p.id = u.property_id |
| 48 | | JOIN Listing lst ON u.id = lst.unit_id |
| 49 | | JOIN Lease l ON lst.id = l.listing_id |
| 50 | | JOIN Payment pay ON l.id = pay.lease_id |
| 51 | | WHERE EXTRACT(YEAR FROM pay.payment_date) = EXTRACT(YEAR FROM CURRENT_DATE) |
| 52 | | AND pay.status = 'завршено' |
| 53 | | GROUP BY a.city |
| 54 | | ORDER BY total_revenue DESC; |
| 55 | | }}} |
| 56 | | |
| 57 | | === 3. Извештај за процент на изнајмени недвижности во однос на објавени огласи за секоја година. |
| | 6 | === 1. Извештај за процент на изнајмени недвижности во однос на објавени огласи за секоја година. |
| 118 | | === 5. Извештај за цени за изнајмување на недвижности (просечна, минимална, максимална и цена по метар квадратен) согласно категорија на објект, град, број на соби, големина на објект. |
| 119 | | {{{ |
| 120 | | |
| 121 | | SELECT |
| 122 | | pt.name AS property_type, |
| 123 | | a.city, |
| 124 | | u.bedrooms, |
| | 67 | === 3. Детален месечен извештај за приходите, наплатата, останатиот долг, ненаплатените и активните изнајмувања и нерешените сервисни барања на изнајмувачите |
| | 68 | |
| | 69 | |
| | 70 | {{{ |
| | 71 | WITH month_period AS ( |
| | 72 | SELECT |
| | 73 | DATE_TRUNC('month', CURRENT_DATE) - INTERVAL '1 month' AS month_start, |
| | 74 | (DATE_TRUNC('month', CURRENT_DATE) - INTERVAL '1 month') + INTERVAL '1 month - 1 day' AS month_end |
| | 75 | ), |
| | 76 | landlords AS ( |
| | 77 | SELECT lp.id AS landlord_id, u.first_name || ' ' || u.last_name AS landlord_name |
| | 78 | FROM domify.LandlordProfile lp |
| | 79 | JOIN domify.UserD u ON lp.id = u.id |
| | 80 | ), |
| | 81 | total_due_cte AS ( |
| | 82 | SELECT |
| | 83 | l.landlord_id, |
| | 84 | COALESCE(SUM(l.rent_amount), 0) AS total_due |
| | 85 | FROM domify.Lease l |
| | 86 | CROSS JOIN month_period mp |
| | 87 | WHERE l.start_date <= mp.month_end |
| | 88 | AND l.end_date >= mp.month_start |
| | 89 | GROUP BY l.landlord_id |
| | 90 | ), |
| | 91 | total_paid_cte AS ( |
| | 92 | SELECT |
| | 93 | l.landlord_id, |
| | 94 | COALESCE(SUM(p.amount), 0) AS total_paid |
| | 95 | FROM domify.Payment p |
| | 96 | JOIN domify.Lease l ON p.lease_id = l.id |
| | 97 | CROSS JOIN month_period mp |
| | 98 | WHERE p.payment_date BETWEEN mp.month_start AND mp.month_end |
| | 99 | AND p.status IN ('completed','paid') |
| | 100 | GROUP BY l.landlord_id |
| | 101 | ), |
| | 102 | late_count_cte AS ( |
| | 103 | SELECT |
| | 104 | l.landlord_id, |
| | 105 | COUNT(*) AS late_count |
| | 106 | FROM domify.Lease l |
| | 107 | CROSS JOIN month_period mp |
| | 108 | WHERE l.start_date <= mp.month_end |
| | 109 | AND l.end_date >= mp.month_start |
| | 110 | AND NOT EXISTS ( |
| | 111 | SELECT 1 |
| | 112 | FROM domify.Payment p |
| | 113 | WHERE p.lease_id = l.id |
| | 114 | AND p.payment_date BETWEEN mp.month_start AND mp.month_end |
| | 115 | AND p.status IN ('completed','paid') |
| | 116 | ) |
| | 117 | GROUP BY l.landlord_id |
| | 118 | ), |
| | 119 | active_leases_cte AS ( |
| | 120 | SELECT |
| | 121 | l.landlord_id, |
| | 122 | COUNT(*) AS active_leases |
| | 123 | FROM domify.Lease l |
| | 124 | WHERE l.start_date <= CURRENT_DATE |
| | 125 | AND l.end_date >= CURRENT_DATE |
| | 126 | GROUP BY l.landlord_id |
| | 127 | ), |
| | 128 | pending_services_cte AS ( |
| | 129 | SELECT |
| | 130 | l.landlord_id, |
| | 131 | COUNT(*) AS pending_services |
| | 132 | FROM domify.ServiceRequest sr |
| | 133 | JOIN domify.Lease l ON sr.lease_id = l.id |
| | 134 | WHERE sr.status IN ('pending','in_progress') |
| | 135 | GROUP BY l.landlord_id |
| | 136 | ) |
| | 137 | SELECT |
| | 138 | ld.landlord_id, |
| | 139 | ld.landlord_name, |
| | 140 | td.total_due, |
| | 141 | tp.total_paid, |
| | 142 | (td.total_due - tp.total_paid) AS remaining_debt, |
| | 143 | lc.late_count, |
| | 144 | al.active_leases, |
| | 145 | ps.pending_services |
| | 146 | FROM landlords ld |
| | 147 | CROSS JOIN month_period mp |
| | 148 | LEFT JOIN total_due_cte td ON ld.landlord_id = td.landlord_id |
| | 149 | LEFT JOIN total_paid_cte tp ON ld.landlord_id = tp.landlord_id |
| | 150 | LEFT JOIN late_count_cte lc ON ld.landlord_id = lc.landlord_id |
| | 151 | LEFT JOIN active_leases_cte al ON ld.landlord_id = al.landlord_id |
| | 152 | LEFT JOIN pending_services_cte ps ON ld.landlord_id = ps.landlord_id |
| | 153 | ORDER BY ld.landlord_name; |
| | 154 | |
| | 155 | }}} |
| | 156 | === 4. Детален извештај за историјата на плаќања, задоцнети и тековни обврски, просечна кирија и оценка на платежната дисциплина на изнајмувачите |
| | 157 | {{{ |
| | 158 | WITH TenantPaymentStats AS ( |
| | 159 | SELECT |
| | 160 | t.id as tenant_id, |
| | 161 | CONCAT(u.first_name, ' ', u.last_name) as tenant_name, |
| | 162 | u.rating as tenant_rating, |
| | 163 | COUNT(DISTINCT le.id) as total_leases, |
| | 164 | COUNT(DISTINCT pay.id) as total_payments, |
| | 165 | SUM(CASE WHEN pay.status = 'завршено' THEN pay.amount ELSE 0 END) as total_paid, |
| | 166 | SUM(CASE WHEN pay.status = 'доцнење' THEN pay.amount ELSE 0 END) as late_payments_amount, |
| | 167 | COUNT(CASE WHEN pay.status = 'доцнење' THEN 1 END) as late_payment_count, |
| | 168 | COUNT(CASE WHEN pay.status = 'во тек' THEN 1 END) as pending_payment_count, |
| | 169 | AVG(le.rent_amount) as avg_rent_amount, |
| | 170 | MIN(le.start_date) as first_lease_date, |
| | 171 | MAX(le.end_date) as latest_lease_end |
| | 172 | FROM TenantProfile t |
| | 173 | JOIN UserD u ON t.id = u.id |
| | 174 | LEFT JOIN Lease le ON t.id = le.tenant_id |
| | 175 | LEFT JOIN Payment pay ON le.id = pay.lease_id |
| | 176 | GROUP BY t.id, u.first_name, u.last_name, u.rating |
| | 177 | ) |
| | 178 | SELECT |
| | 179 | tenant_id, |
| | 180 | tenant_name, |
| | 181 | tenant_rating, |
| | 182 | total_leases, |
| | 183 | total_payments, |
| | 184 | total_paid, |
| | 185 | late_payments_amount, |
| | 186 | late_payment_count, |
| | 187 | pending_payment_count, |
| | 188 | ROUND((late_payment_count * 100.0 / NULLIF(total_payments, 0)), 2) as late_payment_percentage, |
| | 189 | avg_rent_amount, |
| | 190 | first_lease_date, |
| | 191 | latest_lease_end, |
| 126 | | WHEN u.area_sq_m < 50 THEN 'Мала (<50м²)' |
| 127 | | WHEN u.area_sq_m < 80 THEN 'Средна (50-80м²)' |
| 128 | | ELSE 'Голема (>80м²)' |
| 129 | | END AS size_category, |
| 130 | | COUNT(l.id) AS lease_count, |
| 131 | | ROUND(AVG(l.rent_amount), 2) AS avg_rent, |
| 132 | | ROUND(MIN(l.rent_amount), 2) AS min_rent, |
| 133 | | ROUND(MAX(l.rent_amount), 2) AS max_rent, |
| 134 | | ROUND(AVG(l.rent_amount / u.area_sq_m), 2) AS price_per_sqm |
| 135 | | FROM Lease l |
| 136 | | JOIN Listing li ON l.listing_id = li.id |
| 137 | | JOIN Unit u ON li.unit_id = u.id |
| 138 | | JOIN Property p ON u.property_id = p.id |
| 139 | | JOIN PropertyType pt ON p.property_type_id = pt.id |
| 140 | | JOIN Address a ON p.address_id = a.id |
| 141 | | WHERE l.start_date >= CURRENT_DATE - INTERVAL '12 months' |
| 142 | | GROUP BY pt.name, a.city, u.bedrooms, size_category |
| 143 | | HAVING COUNT(l.id) >= 1 |
| 144 | | ORDER BY a.city, pt.name, u.bedrooms; |
| 145 | | }}} |
| 146 | | |
| 147 | | === 6. Извештај за последната година за тоа колку просечно денови во секој месец огласите биле изложени пред да биде склучен договор за нив. |
| 148 | | {{{ |
| 149 | | SELECT |
| 150 | | EXTRACT(YEAR FROM li.available_from) AS year, |
| 151 | | EXTRACT(MONTH FROM li.available_from) AS month, |
| 152 | | COUNT(*) AS total_listings, |
| 153 | | AVG(l.start_date - li.available_from) AS avg_days_on_market |
| 154 | | FROM Listing li |
| 155 | | JOIN Lease l ON li.id = l.listing_id |
| 156 | | WHERE li.available_from >= CURRENT_DATE - INTERVAL '365 days' AND l.start_date BETWEEN li.available_from AND li.available_to |
| 157 | | GROUP BY year, month |
| 158 | | ORDER BY year, month; |
| 159 | | }}} |
| 160 | | |
| 161 | | === 7. Извештај за број на барања за поправка/сервисирање на недвижност по град |
| 162 | | {{{ |
| 163 | | SELECT |
| 164 | | a.city, |
| 165 | | COUNT(sr.id) AS request_count |
| 166 | | FROM ServiceRequest sr |
| 167 | | JOIN Lease l ON sr.lease_id = l.id |
| 168 | | JOIN Listing li ON l.listing_id = li.id |
| 169 | | JOIN Unit u ON li.unit_id = u.id |
| 170 | | JOIN Property p ON u.property_id = p.id |
| 171 | | JOIN Address a ON p.address_id = a.id |
| 172 | | WHERE EXTRACT(YEAR FROM sr.request_date) = EXTRACT(YEAR FROM CURRENT_DATE) |
| 173 | | GROUP BY a.city |
| 174 | | ORDER BY request_count DESC |
| 175 | | }}} |
| 176 | | |
| 177 | | === 8. Извештај за заинтересираност на изнајмувачи, издавачи со најмногу заинтересирани огласи сортирани по популарност |
| 178 | | |
| 179 | | {{{ |
| 180 | | SELECT |
| 181 | | u.first_name, |
| 182 | | u.last_name, |
| 183 | | u.email, |
| 184 | | a.city, |
| 185 | | COUNT(DISTINCT li.id) AS total_listings, |
| 186 | | COUNT(i.tenant_profile_id) AS total_interested_tenants, |
| 187 | | ROUND(COUNT(i.tenant_profile_id) / COUNT(DISTINCT li.id), 2) AS avg_interest_per_listing |
| 188 | | FROM LandlordProfile lp |
| 189 | | JOIN UserD u ON lp.id = u.id |
| 190 | | JOIN Property p ON p.owner_id = u.id |
| 191 | | JOIN Unit un ON un.property_id = p.id |
| 192 | | JOIN Listing li ON li.unit_id = un.id |
| 193 | | JOIN Address a ON p.address_id = a.id |
| 194 | | LEFT JOIN Interested i ON li.id = i.listing_id |
| 195 | | WHERE li.available_from >= CURRENT_DATE - INTERVAL '12 months' |
| 196 | | GROUP BY u.id, u.first_name, u.last_name, u.email, a.city |
| 197 | | HAVING COUNT(i.tenant_profile_id) > 0 |
| 198 | | ORDER BY total_interested_tenants DESC; |
| 199 | | }}} |
| | 193 | WHEN late_payment_count = 0 THEN 'Одличен' |
| | 194 | WHEN late_payment_count <= 2 THEN 'Добар' |
| | 195 | WHEN late_payment_count <= 5 THEN 'Среден' |
| | 196 | ELSE 'Ризичен' |
| | 197 | END as payment_reliability_score |
| | 198 | FROM TenantPaymentStats |
| | 199 | WHERE total_leases > 0 |
| | 200 | ORDER BY late_payment_percentage ASC, total_paid DESC; |
| | 201 | |
| | 202 | }}} |
| | 203 | === 5. Детален извештај за сервисни барања, стапка на завршување и просечно време на решавање по општина и град |
| | 204 | {{{ |
| | 205 | WITH MaintenanceAnalysis AS ( |
| | 206 | SELECT |
| | 207 | a.municipality, |
| | 208 | a.city, |
| | 209 | sc.name as service_category, |
| | 210 | COUNT(sr.id) as total_requests, |
| | 211 | COUNT(CASE WHEN sr.status = 'завршено' THEN 1 END) as completed_requests, |
| | 212 | COUNT(CASE WHEN sr.status = 'во тек' THEN 1 END) as in_progress_requests, |
| | 213 | COUNT(CASE WHEN sr.status = 'во очекување' THEN 1 END) as pending_requests, |
| | 214 | AVG(CASE |
| | 215 | WHEN sr.status = 'завршено' AND ml.maintenance_date IS NOT NULL |
| | 216 | THEN DATEDIFF(ml.maintenance_date, sr.request_date) |
| | 217 | END) as avg_resolution_days |
| | 218 | FROM ServiceRequest sr |
| | 219 | JOIN ServiceCategory sc ON sr.service_category_id = sc.id |
| | 220 | JOIN Lease le ON sr.lease_id = le.id |
| | 221 | JOIN Listing l ON le.listing_id = l.id |
| | 222 | JOIN Unit u ON l.unit_id = u.id |
| | 223 | JOIN Property p ON u.property_id = p.id |
| | 224 | JOIN Address a ON p.address_id = a.id |
| | 225 | LEFT JOIN MaintenanceLog ml ON sr.id = ml.service_request_id |
| | 226 | GROUP BY a.municipality, a.city, sc.name |
| | 227 | ) |
| | 228 | SELECT |
| | 229 | municipality, |
| | 230 | city, |
| | 231 | service_category, |
| | 232 | total_requests, |
| | 233 | completed_requests, |
| | 234 | in_progress_requests, |
| | 235 | pending_requests, |
| | 236 | ROUND((completed_requests * 100.0 / NULLIF(total_requests, 0)), 2) as completion_rate_percent, |
| | 237 | ROUND(avg_resolution_days, 1) as avg_resolution_days, |
| | 238 | CASE |
| | 239 | WHEN avg_resolution_days <= 2 THEN 'Брзо' |
| | 240 | WHEN avg_resolution_days <= 5 THEN 'Средно' |
| | 241 | WHEN avg_resolution_days <= 10 THEN 'Бавно' |
| | 242 | ELSE 'Многу бавно' |
| | 243 | END as response_time_rating |
| | 244 | FROM MaintenanceAnalysis |
| | 245 | ORDER BY municipality, total_requests DESC; |
| | 246 | |
| | 247 | }}} |
| | 248 | === 6.Анализа на пазарни трендови и изнајмувачка понуда по општина, град и тип на недвижност |
| | 249 | {{{ |
| | 250 | WITH MarketTrends AS ( |
| | 251 | SELECT |
| | 252 | a.municipality, |
| | 253 | a.city, |
| | 254 | pt.name as property_type, |
| | 255 | COUNT(DISTINCT l.id) as total_listings, |
| | 256 | COUNT(DISTINCT CASE WHEN l.status = 'available' THEN l.id END) as available_listings, |
| | 257 | AVG(u.rent_amount) as avg_rent_asking, |
| | 258 | AVG(le.rent_amount) as avg_rent_actual, |
| | 259 | AVG(u.area_sq_m) as avg_unit_size, |
| | 260 | AVG(u.rent_amount / u.area_sq_m) as avg_rent_per_sq_m, |
| | 261 | MIN(u.rent_amount) as min_rent, |
| | 262 | MAX(u.rent_amount) as max_rent, |
| | 263 | COUNT(DISTINCT in_list.tenant_profile_id) as total_interested_tenants |
| | 264 | FROM Address a |
| | 265 | JOIN Property p ON a.id = p.address_id |
| | 266 | JOIN PropertyType pt ON p.property_type_id = pt.id |
| | 267 | JOIN Unit u ON p.id = u.property_id |
| | 268 | JOIN Listing l ON u.id = l.unit_id |
| | 269 | LEFT JOIN Lease le ON l.id = le.listing_id |
| | 270 | LEFT JOIN Interested in_list ON l.id = in_list.listing_id |
| | 271 | GROUP BY a.municipality, a.city, pt.name |
| | 272 | ) |
| | 273 | SELECT |
| | 274 | municipality, |
| | 275 | city, |
| | 276 | property_type, |
| | 277 | total_listings, |
| | 278 | available_listings, |
| | 279 | ROUND((available_listings * 100.0 / NULLIF(total_listings, 0)), 2) as availability_rate, |
| | 280 | ROUND(avg_rent_asking, 2) as avg_rent_asking, |
| | 281 | ROUND(avg_rent_actual, 2) as avg_rent_actual, |
| | 282 | ROUND((avg_rent_actual - avg_rent_asking), 2) as rent_variance, |
| | 283 | ROUND(avg_unit_size, 1) as avg_unit_size_sq_m, |
| | 284 | ROUND(avg_rent_per_sq_m, 2) as avg_rent_per_sq_m, |
| | 285 | min_rent, |
| | 286 | max_rent, |
| | 287 | total_interested_tenants, |
| | 288 | ROUND(total_interested_tenants / NULLIF(available_listings, 0), 2) as interest_ratio, |
| | 289 | CASE |
| | 290 | WHEN availability_rate > 75 THEN 'Висока понуда' |
| | 291 | WHEN availability_rate > 50 THEN 'Умерена понуда' |
| | 292 | WHEN availability_rate > 25 THEN 'Ограничена понуда' |
| | 293 | ELSE 'Ниска Понуда' |
| | 294 | END as market_availability_status |
| | 295 | FROM MarketTrends |
| | 296 | WHERE total_listings > 0 |
| | 297 | ORDER BY municipality, avg_rent_per_sq_m DESC; |
| | 298 | |
| | 299 | }}} |
| | 300 | |