feat: add dashboard summary endpoint and related models, queries, and services

This commit is contained in:
Tran Anh Tuan
2026-05-13 17:53:32 +07:00
parent b815111b8f
commit 383bed757d
12 changed files with 928 additions and 0 deletions

151
sqlc_gen/dashboard.sql.go Normal file
View File

@@ -0,0 +1,151 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: dashboard.sql
package db
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const countLowStockComponents = `-- name: CountLowStockComponents :one
SELECT COUNT(*) FROM components
WHERE total_quantity <= min_quantity
`
func (q *Queries) CountLowStockComponents(ctx context.Context) (int64, error) {
row := q.db.QueryRow(ctx, countLowStockComponents)
var count int64
err := row.Scan(&count)
return count, err
}
const countPendingInvoices = `-- name: CountPendingInvoices :one
SELECT COUNT(*) FROM invoices
WHERE status IN ('draft', 'pending')
`
func (q *Queries) CountPendingInvoices(ctx context.Context) (int64, error) {
row := q.db.QueryRow(ctx, countPendingInvoices)
var count int64
err := row.Scan(&count)
return count, err
}
const getAbnormalItemCounts = `-- name: GetAbnormalItemCounts :many
SELECT ci.status, COUNT(*) AS count
FROM component_items ci
JOIN containers con ON ci.container_id = con.id
JOIN shelves s ON con.shelf_id = s.id
JOIN cabinets cab ON s.cabinet_id = cab.id
JOIN rooms r ON cab.room_id = r.id
WHERE ci.status != 'normal'
AND ($1::bigint IS NULL OR r.warehouse_id = $1::bigint)
GROUP BY ci.status
`
type GetAbnormalItemCountsRow struct {
Status ComponentItemStatusEnum `db:"status" json:"status"`
Count int64 `db:"count" json:"count"`
}
func (q *Queries) GetAbnormalItemCounts(ctx context.Context, warehouseID pgtype.Int8) ([]GetAbnormalItemCountsRow, error) {
rows, err := q.db.Query(ctx, getAbnormalItemCounts, warehouseID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetAbnormalItemCountsRow
for rows.Next() {
var i GetAbnormalItemCountsRow
if err := rows.Scan(&i.Status, &i.Count); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getContainerStats = `-- name: GetContainerStats :one
SELECT
COUNT(*) AS total_containers,
COUNT(*) - COUNT(DISTINCT ci.container_id) AS empty_containers
FROM containers c
JOIN shelves s ON c.shelf_id = s.id
JOIN cabinets cab ON s.cabinet_id = cab.id
JOIN rooms r ON cab.room_id = r.id
LEFT JOIN component_items ci ON c.id = ci.container_id
WHERE $1::bigint IS NULL OR r.warehouse_id = $1::bigint
`
type GetContainerStatsRow struct {
TotalContainers int64 `db:"total_containers" json:"totalContainers"`
EmptyContainers int32 `db:"empty_containers" json:"emptyContainers"`
}
func (q *Queries) GetContainerStats(ctx context.Context, warehouseID pgtype.Int8) (GetContainerStatsRow, error) {
row := q.db.QueryRow(ctx, getContainerStats, warehouseID)
var i GetContainerStatsRow
err := row.Scan(&i.TotalContainers, &i.EmptyContainers)
return i, err
}
const getTodayInvoiceCounts = `-- name: GetTodayInvoiceCounts :many
SELECT type, COUNT(*) AS count
FROM invoices
WHERE created_at::date = CURRENT_DATE
GROUP BY type
`
type GetTodayInvoiceCountsRow struct {
Type InvoiceTypeEnum `db:"type" json:"type"`
Count int64 `db:"count" json:"count"`
}
func (q *Queries) GetTodayInvoiceCounts(ctx context.Context) ([]GetTodayInvoiceCountsRow, error) {
rows, err := q.db.Query(ctx, getTodayInvoiceCounts)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetTodayInvoiceCountsRow
for rows.Next() {
var i GetTodayInvoiceCountsRow
if err := rows.Scan(&i.Type, &i.Count); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getTotalComponentStats = `-- name: GetTotalComponentStats :one
SELECT COUNT(DISTINCT ci.component_id) AS total_types, COALESCE(SUM(ci.quantity), 0)::bigint AS total_quantity
FROM component_items ci
JOIN containers con ON ci.container_id = con.id
JOIN shelves s ON con.shelf_id = s.id
JOIN cabinets cab ON s.cabinet_id = cab.id
JOIN rooms r ON cab.room_id = r.id
WHERE $1::bigint IS NULL OR r.warehouse_id = $1::bigint
`
type GetTotalComponentStatsRow struct {
TotalTypes int64 `db:"total_types" json:"totalTypes"`
TotalQuantity int64 `db:"total_quantity" json:"totalQuantity"`
}
func (q *Queries) GetTotalComponentStats(ctx context.Context, warehouseID pgtype.Int8) (GetTotalComponentStatsRow, error) {
row := q.db.QueryRow(ctx, getTotalComponentStats, warehouseID)
var i GetTotalComponentStatsRow
err := row.Scan(&i.TotalTypes, &i.TotalQuantity)
return i, err
}

View File

@@ -8,10 +8,13 @@ import (
"context"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
)
type Querier interface {
AssignRoleToUser(ctx context.Context, arg AssignRoleToUserParams) (UserRole, error)
CountLowStockComponents(ctx context.Context) (int64, error)
CountPendingInvoices(ctx context.Context) (int64, error)
CountUsersByRoleID(ctx context.Context, roleID uuid.UUID) (int64, error)
CreateAlternativeComponent(ctx context.Context, arg CreateAlternativeComponentParams) (AlternativeComponent, error)
CreateCabinet(ctx context.Context, arg CreateCabinetParams) (Cabinet, error)
@@ -46,6 +49,7 @@ type Querier interface {
DeleteShelve(ctx context.Context, id int64) (int64, error)
DeleteWarehouse(ctx context.Context, id int64) (int64, error)
FindComponentItem(ctx context.Context, componentid int64) ([]FindComponentItemRow, error)
GetAbnormalItemCounts(ctx context.Context, warehouseID pgtype.Int8) ([]GetAbnormalItemCountsRow, error)
GetAlternativeComponentByID(ctx context.Context, id int64) (AlternativeComponent, error)
GetCabinetByID(ctx context.Context, id int64) (Cabinet, error)
GetComponentByID(ctx context.Context, id int64) (Component, error)
@@ -54,6 +58,7 @@ type Querier interface {
GetComponentItemByID(ctx context.Context, id int64) (ComponentItem, error)
GetComponentTypeByID(ctx context.Context, id int64) (ComponentType, error)
GetContainerByID(ctx context.Context, id int64) (Container, error)
GetContainerStats(ctx context.Context, warehouseID pgtype.Int8) (GetContainerStatsRow, error)
GetInvoiceByID(ctx context.Context, id int64) (Invoice, error)
GetInvoiceConfigByID(ctx context.Context, id int64) (InvoiceConfig, error)
GetInvoiceConfigItemByID(ctx context.Context, id int64) (InvoiceConfigItem, error)
@@ -62,6 +67,8 @@ type Querier interface {
GetRoleByID(ctx context.Context, id uuid.UUID) (Role, error)
GetRoomByID(ctx context.Context, id int64) (Room, error)
GetShelveByID(ctx context.Context, id int64) (Shelf, error)
GetTodayInvoiceCounts(ctx context.Context) ([]GetTodayInvoiceCountsRow, error)
GetTotalComponentStats(ctx context.Context, warehouseID pgtype.Int8) (GetTotalComponentStatsRow, error)
GetUserByEmail(ctx context.Context, email string) (User, error)
GetUserByID(ctx context.Context, id uuid.UUID) (User, error)
GetUserByUsername(ctx context.Context, username string) (User, error)