Added analytics by transactions

This commit is contained in:
2026-04-11 11:37:48 +03:00
parent b66be96033
commit 8e074db55f
8 changed files with 346 additions and 1 deletions
+50 -1
View File
@@ -25,6 +25,7 @@ func (router *TransactionsRouter) RegisterRoutes(r *gin.RouterGroup) {
{
transactions.POST("", router.Create)
transactions.GET("", router.List)
transactions.GET("/analytics", router.Analytics)
transactions.GET("/:id", router.Read)
transactions.PATCH("/:id", router.Update)
transactions.DELETE("/:id", router.Delete)
@@ -114,6 +115,53 @@ func (router *TransactionsRouter) List(c *gin.Context) {
c.JSON(http.StatusOK, dto.TransactionsToListResponse(transactions))
}
// Analytics GoDoc
// @Summary Получить аналитику по транзакциям
// @Description Возвращает расходы, доходы и total за период. При фильтре по type второй тип возвращается как 0.
// @Tags Transactions
// @Accept json
// @Produce json
// @Param family_id query int false "Family ID"
// @Param type query string false "Transaction type: income or expense"
// @Param date_from query string true "RFC3339 start datetime"
// @Param date_to query string true "RFC3339 end datetime"
// @Success 200 {object} dto.TransactionAnalyticsResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 500 {object} dto.ErrorResponse
// @Router /transactions/analytics [get]
func (router *TransactionsRouter) Analytics(c *gin.Context) {
var query dto.TransactionAnalyticsQuery
if err := c.ShouldBindQuery(&query); err != nil {
c.JSON(http.StatusBadRequest, dto.ErrorResponse{Message: err.Error()})
return
}
dateFrom, err := time.Parse(time.RFC3339, query.DateFrom)
if err != nil {
c.JSON(http.StatusBadRequest, dto.ErrorResponse{Message: "date_from must be RFC3339"})
return
}
dateTo, err := time.Parse(time.RFC3339, query.DateTo)
if err != nil {
c.JSON(http.StatusBadRequest, dto.ErrorResponse{Message: "date_to must be RFC3339"})
return
}
analytics, err := router.service.Analytics(c.Request.Context(), domain.TransactionAnalyticsFilter{
FamilyID: query.FamilyID,
Type: query.Type,
DateFrom: dateFrom,
DateTo: dateTo,
})
if err != nil {
handleTransactionError(c, err)
return
}
c.JSON(http.StatusOK, dto.TransactionAnalyticsToResponse(analytics))
}
// Read GoDoc
// @Summary Получить транзакцию по ID
// @Description Возвращает транзакцию по ее внутреннему ID
@@ -228,7 +276,8 @@ func handleTransactionError(c *gin.Context, err error) {
c.JSON(http.StatusNotFound, dto.ErrorResponse{Message: err.Error()})
case errors.Is(err, services.ErrTransactionPatch),
errors.Is(err, services.ErrReceiptLinkConflict),
errors.Is(err, services.ErrInvalidTransaction):
errors.Is(err, services.ErrInvalidTransaction),
errors.Is(err, services.ErrInvalidAnalytics):
c.JSON(http.StatusBadRequest, dto.ErrorResponse{Message: err.Error()})
case errors.Is(err, services.ErrReceiptNotFound):
c.JSON(http.StatusNotFound, dto.ErrorResponse{Message: err.Error()})