feat: add dashboard summary endpoint and related models, queries, and services
This commit is contained in:
34
internal/mapper/dashboard_mapper.go
Normal file
34
internal/mapper/dashboard_mapper.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"wm-backend/internal/models"
|
||||
db "wm-backend/sqlc_gen"
|
||||
)
|
||||
|
||||
func ToDomainTotalComponentStats(r db.GetTotalComponentStatsRow) models.TotalComponentStats {
|
||||
return models.TotalComponentStats{
|
||||
TotalTypes: r.TotalTypes,
|
||||
TotalQuantity: r.TotalQuantity,
|
||||
}
|
||||
}
|
||||
|
||||
func ToDomainAbnormalAlert(r db.GetAbnormalItemCountsRow) models.AbnormalAlert {
|
||||
return models.AbnormalAlert{
|
||||
Status: string(r.Status),
|
||||
Count: r.Count,
|
||||
}
|
||||
}
|
||||
|
||||
func ToDomainTodayInvoiceCount(r db.GetTodayInvoiceCountsRow) models.TodayInvoiceCount {
|
||||
return models.TodayInvoiceCount{
|
||||
Type: string(r.Type),
|
||||
Count: r.Count,
|
||||
}
|
||||
}
|
||||
|
||||
func ToDomainContainerStats(r db.GetContainerStatsRow) models.ContainerStats {
|
||||
return models.ContainerStats{
|
||||
TotalContainers: r.TotalContainers,
|
||||
EmptyContainers: int64(r.EmptyContainers),
|
||||
}
|
||||
}
|
||||
30
internal/models/dashboard_model.go
Normal file
30
internal/models/dashboard_model.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package models
|
||||
|
||||
type TotalComponentStats struct {
|
||||
TotalTypes int64 `json:"totalTypes"`
|
||||
TotalQuantity int64 `json:"totalQuantity"`
|
||||
}
|
||||
|
||||
type AbnormalAlert struct {
|
||||
Status string `json:"status"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
type TodayInvoiceCount struct {
|
||||
Type string `json:"type"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
type ContainerStats struct {
|
||||
TotalContainers int64 `json:"totalContainers"`
|
||||
EmptyContainers int64 `json:"emptyContainers"`
|
||||
}
|
||||
|
||||
type DashboardSummary struct {
|
||||
TotalComponents TotalComponentStats `json:"totalComponents"`
|
||||
PendingInvoices int64 `json:"pendingInvoices"`
|
||||
LowStockComponents int64 `json:"lowStockComponents"`
|
||||
AbnormalAlerts []AbnormalAlert `json:"abnormalAlerts"`
|
||||
TodayInvoices []TodayInvoiceCount `json:"todayInvoices"`
|
||||
EmptyContainers ContainerStats `json:"emptyContainers"`
|
||||
}
|
||||
61
internal/repositories/dashboard_repository.go
Normal file
61
internal/repositories/dashboard_repository.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"wm-backend/internal/mapper"
|
||||
"wm-backend/internal/models"
|
||||
db "wm-backend/sqlc_gen"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func GetDashboardSummary(ctx context.Context, queries *db.Queries, warehouseID pgtype.Int8) (models.DashboardSummary, error) {
|
||||
totalStats, err := queries.GetTotalComponentStats(ctx, warehouseID)
|
||||
if err != nil {
|
||||
return models.DashboardSummary{}, err
|
||||
}
|
||||
|
||||
pendingInvoices, err := queries.CountPendingInvoices(ctx)
|
||||
if err != nil {
|
||||
return models.DashboardSummary{}, err
|
||||
}
|
||||
|
||||
lowStockCount, err := queries.CountLowStockComponents(ctx)
|
||||
if err != nil {
|
||||
return models.DashboardSummary{}, err
|
||||
}
|
||||
|
||||
abnormalRows, err := queries.GetAbnormalItemCounts(ctx, warehouseID)
|
||||
if err != nil {
|
||||
return models.DashboardSummary{}, err
|
||||
}
|
||||
|
||||
todayInvoiceRows, err := queries.GetTodayInvoiceCounts(ctx)
|
||||
if err != nil {
|
||||
return models.DashboardSummary{}, err
|
||||
}
|
||||
|
||||
containerStats, err := queries.GetContainerStats(ctx, warehouseID)
|
||||
if err != nil {
|
||||
return models.DashboardSummary{}, err
|
||||
}
|
||||
|
||||
abnormalAlerts := make([]models.AbnormalAlert, 0, len(abnormalRows))
|
||||
for _, r := range abnormalRows {
|
||||
abnormalAlerts = append(abnormalAlerts, mapper.ToDomainAbnormalAlert(r))
|
||||
}
|
||||
|
||||
todayInvoices := make([]models.TodayInvoiceCount, 0, len(todayInvoiceRows))
|
||||
for _, r := range todayInvoiceRows {
|
||||
todayInvoices = append(todayInvoices, mapper.ToDomainTodayInvoiceCount(r))
|
||||
}
|
||||
|
||||
return models.DashboardSummary{
|
||||
TotalComponents: mapper.ToDomainTotalComponentStats(totalStats),
|
||||
PendingInvoices: pendingInvoices,
|
||||
LowStockComponents: lowStockCount,
|
||||
AbnormalAlerts: abnormalAlerts,
|
||||
TodayInvoices: todayInvoices,
|
||||
EmptyContainers: mapper.ToDomainContainerStats(containerStats),
|
||||
}, nil
|
||||
}
|
||||
@@ -152,6 +152,11 @@ func NewRouter() *gin.Engine {
|
||||
alternativeComponent.PUT("/:id", utils.AsyncHandler(services.AlternativeComponentUpdate))
|
||||
alternativeComponent.DELETE("/:id", utils.AsyncHandler(services.AlternativeComponentDelete))
|
||||
}
|
||||
|
||||
dashboard := protected.Group(constants.API_GROUP_DASHBOARD)
|
||||
{
|
||||
dashboard.GET("/summary", utils.AsyncHandler(services.DashboardSummary))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
43
internal/services/dashboard_service.go
Normal file
43
internal/services/dashboard_service.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"wm-backend/global"
|
||||
"wm-backend/internal/repositories"
|
||||
"wm-backend/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// @Summary Get dashboard summary
|
||||
// @Description Retrieve dashboard summary with key statistics
|
||||
// @Tags dashboard
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param warehouse_id query int false "Filter by warehouse ID"
|
||||
// @Success 200 {object} response.SuccessResponse{data=models.DashboardSummary}
|
||||
// @Failure 500 {object} response.ErrorResponse
|
||||
// @Router /v1/dashboard/summary [get]
|
||||
func DashboardSummary(c *gin.Context) error {
|
||||
var warehouseID pgtype.Int8
|
||||
if raw := c.Query("warehouse_id"); raw != "" {
|
||||
id, err := strconv.ParseInt(raw, 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequestError(c, http.StatusBadRequest, "Invalid warehouse_id")
|
||||
return nil
|
||||
}
|
||||
warehouseID = pgtype.Int8{Int64: id, Valid: true}
|
||||
}
|
||||
|
||||
summary, err := repositories.GetDashboardSummary(c.Request.Context(), global.Queries, warehouseID)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Error when Get Dashboard Summary")
|
||||
response.InternalServerError(c, http.StatusInternalServerError, "Failed to get dashboard summary")
|
||||
return nil
|
||||
}
|
||||
response.Ok(c, "Success", summary)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user