lot summaries

deepsource-autofix-76c6eb20
Dan Gowans 2022-09-27 10:44:04 -04:00
parent 89a559d2b5
commit c1707043e6
9 changed files with 267 additions and 15 deletions

View File

@ -1,14 +1,23 @@
import * as configFunctions from "../../helpers/functions.config.js"; import * as configFunctions from "../../helpers/functions.config.js";
import { getMap } from "../../helpers/lotOccupancyDB/getMap.js"; import { getMap } from "../../helpers/lotOccupancyDB/getMap.js";
import { getLotStatusSummary } from "../../helpers/lotOccupancyDB/getLotStatusSummary.js";
import { getLotTypeSummary } from "../../helpers/lotOccupancyDB/getLotTypeSummary.js";
export const handler = (request, response) => { export const handler = (request, response) => {
const map = getMap(request.params.mapId); const map = getMap(request.params.mapId);
if (!map) { if (!map) {
return response.redirect(configFunctions.getProperty("reverseProxy.urlPrefix") + return response.redirect(configFunctions.getProperty("reverseProxy.urlPrefix") + "/maps/?error=mapIdNotFound");
"/maps/?error=mapIdNotFound");
} }
const lotTypeSummary = getLotTypeSummary({
mapId: map.mapId
});
const lotStatusSummary = getLotStatusSummary({
mapId: map.mapId
});
response.render("map-view", { response.render("map-view", {
headTitle: map.mapName, headTitle: map.mapName,
map map,
lotTypeSummary,
lotStatusSummary
}); });
}; };
export default handler; export default handler;

View File

@ -3,20 +3,31 @@ import type { RequestHandler } from "express";
import * as configFunctions from "../../helpers/functions.config.js"; import * as configFunctions from "../../helpers/functions.config.js";
import { getMap } from "../../helpers/lotOccupancyDB/getMap.js"; import { getMap } from "../../helpers/lotOccupancyDB/getMap.js";
import { getLotStatusSummary } from "../../helpers/lotOccupancyDB/getLotStatusSummary.js";
import { getLotTypeSummary } from "../../helpers/lotOccupancyDB/getLotTypeSummary.js";
export const handler: RequestHandler = (request, response) => { export const handler: RequestHandler = (request, response) => {
const map = getMap(request.params.mapId); const map = getMap(request.params.mapId);
if (!map) { if (!map) {
return response.redirect( return response.redirect(
configFunctions.getProperty("reverseProxy.urlPrefix") + configFunctions.getProperty("reverseProxy.urlPrefix") + "/maps/?error=mapIdNotFound"
"/maps/?error=mapIdNotFound"
); );
} }
const lotTypeSummary = getLotTypeSummary({
mapId: map.mapId
});
const lotStatusSummary = getLotStatusSummary({
mapId: map.mapId
});
response.render("map-view", { response.render("map-view", {
headTitle: map.mapName, headTitle: map.mapName,
map map,
lotTypeSummary,
lotStatusSummary
}); });
}; };

View File

@ -0,0 +1,9 @@
import type * as recordTypes from "../../types/recordTypes";
interface GetFilters {
mapId?: number | string;
}
interface LotStatusSummary extends recordTypes.LotStatus {
lotCount: number;
}
export declare const getLotStatusSummary: (filters?: GetFilters) => LotStatusSummary[];
export default getLotStatusSummary;

View File

@ -0,0 +1,24 @@
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
export const getLotStatusSummary = (filters) => {
const database = sqlite(databasePath, {
readonly: true
});
let sqlWhereClause = " where l.recordDelete_timeMillis is null";
const sqlParameters = [];
if (filters && filters.mapId) {
sqlWhereClause += " and l.mapId = ?";
sqlParameters.push(filters.mapId);
}
const lotStatuses = database
.prepare("select s.lotStatusId, s.lotStatus, count(l.lotId) as lotCount" +
" from Lots l" +
" left join LotStatuses s on l.lotStatusId = s.lotStatusId" +
sqlWhereClause +
" group by s.lotStatusId, s.lotStatus, s.orderNumber" +
" order by s.orderNumber")
.all(sqlParameters);
database.close();
return lotStatuses;
};
export default getLotStatusSummary;

View File

@ -0,0 +1,44 @@
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
import type * as recordTypes from "../../types/recordTypes";
interface GetFilters {
mapId?: number | string;
}
interface LotStatusSummary extends recordTypes.LotStatus {
lotCount: number;
}
export const getLotStatusSummary = (filters?: GetFilters): LotStatusSummary[] => {
const database = sqlite(databasePath, {
readonly: true
});
let sqlWhereClause = " where l.recordDelete_timeMillis is null";
const sqlParameters = [];
if (filters && filters.mapId) {
sqlWhereClause += " and l.mapId = ?";
sqlParameters.push(filters.mapId);
}
const lotStatuses: LotStatusSummary[] = database
.prepare(
"select s.lotStatusId, s.lotStatus, count(l.lotId) as lotCount" +
" from Lots l" +
" left join LotStatuses s on l.lotStatusId = s.lotStatusId" +
sqlWhereClause +
" group by s.lotStatusId, s.lotStatus, s.orderNumber" +
" order by s.orderNumber"
)
.all(sqlParameters);
database.close();
return lotStatuses;
};
export default getLotStatusSummary;

View File

@ -0,0 +1,9 @@
import type * as recordTypes from "../../types/recordTypes";
interface GetFilters {
mapId?: number | string;
}
interface LotTypeSummary extends recordTypes.LotType {
lotCount: number;
}
export declare const getLotTypeSummary: (filters?: GetFilters) => LotTypeSummary[];
export default getLotTypeSummary;

View File

@ -0,0 +1,24 @@
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
export const getLotTypeSummary = (filters) => {
const database = sqlite(databasePath, {
readonly: true
});
let sqlWhereClause = " where l.recordDelete_timeMillis is null";
const sqlParameters = [];
if (filters && filters.mapId) {
sqlWhereClause += " and l.mapId = ?";
sqlParameters.push(filters.mapId);
}
const lotTypes = database
.prepare("select t.lotTypeId, t.lotType, count(l.lotId) as lotCount" +
" from Lots l" +
" left join LotTypes t on l.lotTypeId = t.lotTypeId" +
sqlWhereClause +
" group by t.lotTypeId, t.lotType, t.orderNumber" +
" order by t.orderNumber")
.all(sqlParameters);
database.close();
return lotTypes;
};
export default getLotTypeSummary;

View File

@ -0,0 +1,44 @@
import sqlite from "better-sqlite3";
import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js";
import type * as recordTypes from "../../types/recordTypes";
interface GetFilters {
mapId?: number | string;
}
interface LotTypeSummary extends recordTypes.LotType {
lotCount: number;
}
export const getLotTypeSummary = (filters?: GetFilters): LotTypeSummary[] => {
const database = sqlite(databasePath, {
readonly: true
});
let sqlWhereClause = " where l.recordDelete_timeMillis is null";
const sqlParameters = [];
if (filters && filters.mapId) {
sqlWhereClause += " and l.mapId = ?";
sqlParameters.push(filters.mapId);
}
const lotTypes: LotTypeSummary[] = database
.prepare(
"select t.lotTypeId, t.lotType, count(l.lotId) as lotCount" +
" from Lots l" +
" left join LotTypes t on l.lotTypeId = t.lotTypeId" +
sqlWhereClause +
" group by t.lotTypeId, t.lotType, t.orderNumber" +
" order by t.orderNumber"
)
.all(sqlParameters);
database.close();
return lotTypes;
};
export default getLotTypeSummary;

View File

@ -94,16 +94,94 @@
</div> </div>
</div> </div>
<% const lotSearchUrl = urlPrefix + "/lots?mapId=" + map.mapId; %>
<div class="panel"> <div class="panel">
<h2 class="panel-heading"> <div class="panel-heading">
Related Searches <div class="level is-mobile">
</h2> <div class="level-left">
<div class="panel-block"> <div class="level-item">
<a class="button is-link" href="<%= urlPrefix %>/lots?mapId=<%= map.mapId %>"> <h2 class="title is-5 has-text-weight-bold">
<span class="icon is-small"><i class="fas fa-vector-square" aria-hidden="true"></i></span> <%= configFunctions.getProperty("aliases.lot") %> Summaries
<span class="mr-2"><%= configFunctions.getProperty("aliases.lots") %></span> <a class="tag is-link ml-2" href="<%= lotSearchUrl %>">
<span class="tag"><%= map.lotCount %></span> <%= map.lotCount %>
</a> </a>
</h2>
</div>
</div>
<div class="level-right">
<div class="level-item">
<a class="button is-small is-link has-text-weight-normal" href="<%=urlPrefix %>/reports/lots-byMapId?mapId=<%= map.mapId %>" download>
<span class="icon"><i class="fas fa-download" aria-hidden="true"></i></span>
<span>Export All</span>
</a>
</div>
</div>
</div>
</div>
<div class="panel-block is-block">
<% if (map.lotCount === 0) { %>
<div class="message is-info">
<p class="message-body">
There are no <%= configFunctions.getProperty("aliases.lots").toLowerCase() %>
associated with this <%= configFunctions.getProperty("aliases.map").toLowerCase() %>.
</p>
</div>
<% } else { %>
<div class="columns">
<div class="column">
<table class="table is-fullwidth is-striped is-hoverable">
<thead>
<tr>
<th>Type</th>
<th class="has-text-right">
<%= configFunctions.getProperty("aliases.lot") %> Count
</th>
</tr>
</thead>
<tbody>
<% for (const lotType of lotTypeSummary) { %>
<tr>
<td>
<a class="has-text-weight-bold" href="<%= lotSearchUrl %>&lotTypeId=<%= lotType.lotTypeId %>">
<%= lotType.lotType %>
</a>
</td>
<td class="has-text-right">
<%= lotType.lotCount %>
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
<div class="column">
<table class="table is-fullwidth is-striped is-hoverable">
<thead>
<tr>
<th>Status</th>
<th class="has-text-right">
<%= configFunctions.getProperty("aliases.lot") %> Count
</th>
</tr>
</thead>
<tbody>
<% for (const lotStatus of lotStatusSummary) { %>
<tr>
<td>
<a class="has-text-weight-bold" href="<%= lotSearchUrl %>&lotStatusId=<%= lotStatus.lotStatusId %>">
<%= lotStatus.lotStatus %>
</a>
</td>
<td class="has-text-right">
<%= lotStatus.lotCount %>
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
</div>
<% } %>
</div> </div>
</div> </div>