diff --git a/internal/merch/controller.go b/internal/merch/controller.go index 46fa177..2a711f5 100644 --- a/internal/merch/controller.go +++ b/internal/merch/controller.go @@ -42,20 +42,26 @@ func (h *Handler) RegisterRoutes(r *gin.RouterGroup) { chartsGroup.GET("", h.controller.getChartsPrices) chartsGroup.GET("/:uuid", h.controller.getDistinctPrices) + zeroPricesGroup := merchGroup.Group("/zeroprices") + zeroPricesGroup.GET("", h.controller.getZeroPrices) + zeroPricesGroup.DELETE("", h.controller.deleteZeroPrices) + + zeroPricesGroup.DELETE("/period", h.controller.deleteZeroPricesPeriod) + } // create godoc // -// @Summary Create new merch -// @Description Create new merch -// @Tags Merch -// @Accept json -// @Param merch body newMerchDTO true "merch body" -// @Success 201 -// @Failure 400 {object} responses.BadRequest -// @Failure 401 {object} responses.Unauthorized -// @Failure 500 {object} responses.InternalServerError -// @Router /merch/create [POST] +// @Summary Create new merch +// @Description Create new merch +// @Tags Merch +// @Accept json +// @Param merch body newMerchDTO true "merch body" +// @Success 201 +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /merch/create [POST] func (co *controller) create(c *gin.Context) { var newMerch newMerchDTO if err := c.ShouldBindJSON(&newMerch); err != nil { @@ -77,16 +83,16 @@ func (co *controller) getOne(c *gin.Context) {} // getMany godoc // -// @Summary Get all merch -// @Description Get all merch without origins -// @Tags Merch -// @Produce json -// @Success 200 {array} merchDTO -// @Success 204 -// @Failure 400 {object} responses.BadRequest -// @Failure 401 {object} responses.Unauthorized -// @Failure 500 {object} responses.InternalServerError -// @Router /merch/list [GET] +// @Summary Get all merch +// @Description Get all merch without origins +// @Tags Merch +// @Produce json +// @Success 200 {array} merchDTO +// @Success 204 +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /merch/list [GET] func (co *controller) getMany(c *gin.Context) { response, err := co.service.getMany(c, getUserId(c)) if err != nil { @@ -105,18 +111,18 @@ func (co *controller) getMany(c *gin.Context) { // updateMerch godoc // -// @Summary Update merch -// @Description Update merch general info (except extra data) -// @Tags Merch -// @Accept json -// @Param uuid path string true "merch uuid" -// @Param payload body updateMerchDTO true "payload" -// @Produce json -// @Success 200 {object} merchDTO -// @Failure 400 {object} responses.BadRequest -// @Failure 401 {object} responses.Unauthorized -// @Failure 500 {object} responses.InternalServerError -// @Router /merch/{uuid} [PUT] +// @Summary Update merch +// @Description Update merch general info (except extra data) +// @Tags Merch +// @Accept json +// @Param uuid path string true "merch uuid" +// @Param payload body updateMerchDTO true "payload" +// @Produce json +// @Success 200 {object} merchDTO +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /merch/{uuid} [PUT] func (co *controller) updateMerch(c *gin.Context) { merchUuid := c.Param("id") if err := uuid.Validate(merchUuid); err != nil { @@ -150,18 +156,18 @@ func (co *controller) updateMerch(c *gin.Context) { // updateMerch godoc // -// @Summary Update merch extra data -// @Description Update ONLY merch extra data -// @Tags Merch -// @Accept json -// @Param uuid path string true "merch uuid" -// @Param payload body extraDataDTO true "payload" -// @Produce json -// @Success 200 {object} extraDataDTO -// @Failure 400 {object} responses.BadRequest -// @Failure 401 {object} responses.Unauthorized -// @Failure 500 {object} responses.InternalServerError -// @Router /merch/extra/{uuid} [PUT] +// @Summary Update merch extra data +// @Description Update ONLY merch extra data +// @Tags Merch +// @Accept json +// @Param uuid path string true "merch uuid" +// @Param payload body extraDataDTO true "payload" +// @Produce json +// @Success 200 {object} extraDataDTO +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /merch/extra/{uuid} [PUT] func (co *controller) updateExtraData(c *gin.Context) { merchUuid := c.Param("id") if err := uuid.Validate(merchUuid); err != nil { @@ -195,16 +201,16 @@ func (co *controller) updateExtraData(c *gin.Context) { // deleteMerch godoc // -// @Summary Delete merch -// @Description Marks merch and all its extra data as deleted by uuid. -// @Tags Merch -// @Accept json -// @Param uuid path string true "merch uuid" -// @Success 204 -// @Failure 400 {object} responses.BadRequest -// @Failure 401 {object} responses.Unauthorized -// @Failure 500 {object} responses.InternalServerError -// @Router /merch/{uuid} [DELETE] +// @Summary Delete merch +// @Description Marks merch and all its extra data as deleted by uuid. +// @Tags Merch +// @Accept json +// @Param uuid path string true "merch uuid" +// @Success 204 +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /merch/{uuid} [DELETE] func (co *controller) deleteMerch(c *gin.Context) { merchUuid := c.Param("id") if err := uuid.Validate(merchUuid); err != nil { @@ -224,16 +230,16 @@ func (co *controller) deleteMerch(c *gin.Context) { // createOrigin godoc // -// @Summary Create new origin -// @Description Create new origin with name -// @Tags Origins -// @Accept json -// @Param origin body newOriginDTO true "origin body" -// @Success 201 -// @Failure 400 {object} responses.BadRequest -// @Failure 401 {object} responses.Unauthorized -// @Failure 500 {object} responses.InternalServerError -// @Router /merch/origins [POST] +// @Summary Create new origin +// @Description Create new origin with name +// @Tags Origins +// @Accept json +// @Param origin body newOriginDTO true "origin body" +// @Success 201 +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /merch/origins [POST] func (co *controller) createOrigin(c *gin.Context) { var origin *newOriginDTO @@ -255,16 +261,16 @@ func (co *controller) createOrigin(c *gin.Context) { // getOrigins godoc // -// @Summary Get all origins -// @Description Get all origins -// @Tags Origins -// @Produce json -// @Success 200 {object} originsDTO -// @Success 204 -// @Failure 400 {object} responses.BadRequest -// @Failure 401 {object} responses.Unauthorized -// @Failure 500 {object} responses.InternalServerError -// @Router /merch/origins [GET] +// @Summary Get all origins +// @Description Get all origins +// @Tags Origins +// @Produce json +// @Success 200 {object} originsDTO +// @Success 204 +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /merch/origins [GET] func (co *controller) getOrigins(c *gin.Context) { response, err := co.service.getOrigins(c) if err != nil { @@ -279,16 +285,16 @@ func (co *controller) getOrigins(c *gin.Context) { // deleteOrigin godoc // -// @Summary Delete origin -// @Description Marks origin as deleted by name. -// @Tags Origins -// @Accept json -// @Param origin body deleteOriginDTO true "origin body" -// @Success 204 -// @Failure 400 {object} responses.BadRequest -// @Failure 401 {object} responses.Unauthorized -// @Failure 500 {object} responses.InternalServerError -// @Router /merch/origins [DELETE] +// @Summary Delete origin +// @Description Marks origin as deleted by name. +// @Tags Origins +// @Accept json +// @Param origin body deleteOriginDTO true "origin body" +// @Success 204 +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /merch/origins [DELETE] func (co *controller) deleteOrigin(c *gin.Context) { var origin *deleteOriginDTO @@ -310,17 +316,16 @@ func (co *controller) deleteOrigin(c *gin.Context) { // getChartsPrices godoc // -// @Summary Получить цены мерча за период -// @Description Получить цены мерча за период -// @Tags Merch -// @Security BearerAuth -// @Produce json -// @Param days query string false "period in days" -// @Success 200 {array} PricesResponse -// @Failure 400 {object} responses.BadRequest -// @Failure 401 {object} responses.Unauthorized -// @Failure 500 {object} responses.InternalServerError -// @Router /prices [get] +// @Summary Получить цены мерча за период +// @Description Получить цены мерча за период +// @Tags Merch +// @Produce json +// @Param days query string false "period in days" +// @Success 200 {array} PricesResponse +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /prices [get] func (co *controller) getChartsPrices(c *gin.Context) { response, err := co.service.getPrices(c, getUserId(c), getDays(c)) if err != nil { @@ -334,19 +339,18 @@ func (co *controller) getChartsPrices(c *gin.Context) { // getDistinctPrices godoc // -// @Summary Получить перепады цен мерча за период по его merch_uuid -// @Description Получить перепады цен мерча за период по его merch_uuid -// @Tags Merch -// @Security BearerAuth -// @Produce json -// @Param uuid path string true "merch_uuid" -// @Param days query string false "period in days" -// @Success 200 {object} PricesResponse -// @Success 204 -// @Failure 400 {object} responses.BadRequest -// @Failure 401 {object} responses.Unauthorized -// @Failure 500 {object} responses.InternalServerError -// @Router /prices/{uuid} [get] +// @Summary Получить перепады цен мерча за период по его merch_uuid +// @Description Получить перепады цен мерча за период по его merch_uuid +// @Tags Merch +// @Produce json +// @Param uuid path string true "merch_uuid" +// @Param days query string false "period in days" +// @Success 200 {object} PricesResponse +// @Success 204 +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /prices/{uuid} [get] func (co *controller) getDistinctPrices(c *gin.Context) { merchUuid := c.Param("uuid") if merchUuid == "" { @@ -370,3 +374,98 @@ func (co *controller) getDistinctPrices(c *gin.Context) { c.JSON(http.StatusOK, response) } + +// getZeroPrices godoc +// +// @Summary Получить нулевые цены +// @Description Получить нулевые цены +// @Tags Merch zero prices +// @Produce json +// @Success 200 {array} ZeroPrice +// @Success 204 +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /merch/zeroprices [get] +func (co *controller) getZeroPrices(c *gin.Context) { + response, err := co.service.getZeroPrices(c, getUserId(c)) + if err != nil { + c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) + logErr(controllerLogHeader, err) + return + } + + if response == nil { + c.Status(http.StatusNoContent) + } + + c.JSON(http.StatusOK, response) +} + +// deleteZeroPrices godoc +// +// @Summary Пометить нулевые цены как удаленные +// @Description Пометить нулевые цены как удаленные +// @Tags Merch zero prices +// @Security BearerAuth +// @Accept json +// @Param payload body DeleteZeroPrices true "payload" +// @Success 204 +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /merch/zeroprices [delete] +func (co *controller) deleteZeroPrices(c *gin.Context) { + var payload []DeleteZeroPrices + if err := c.ShouldBindJSON(&payload); err != nil { + c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) + logErr(controllerLogHeader, err) + return + } + + if len(payload) < 1 || payload == nil { + c.Status(http.StatusNoContent) + return + } + + if err := co.service.deleteZeroPrices(c, getUserId(c), payload); err != nil { + c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) + logErr(controllerLogHeader, err) + return + } + + c.Status(http.StatusNoContent) +} + +// @Summary Пометить нулевые цены как удаленные за указанный период +// @Description Пометить нулевые цены как удаленные за указанный период +// @Tags Merch zero prices +// @Security BearerAuth +// @Param start query string true "start" +// @Param end query string true "end" +// @Success 204 +// @Failure 400 {object} responses.BadRequest +// @Failure 401 {object} responses.Unauthorized +// @Failure 500 {object} responses.InternalServerError +// @Router /merch/zeroprices/period [delete] +func (co *controller) deleteZeroPricesPeriod(c *gin.Context) { + start, err := co.utils.ParseTime(c.Query("start")) + if err != nil { + c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) + logErr(controllerLogHeader, err) + return + } + + end, err := co.utils.ParseTime(c.Query("end")) + if err != nil { + c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) + logErr(controllerLogHeader, err) + return + } + + if err = co.service.deleteZeroPricesPeriod(c, getUserId(c), start, end); err != nil { + c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) + logErr(controllerLogHeader, err) + return + } + c.Status(http.StatusOK) +} diff --git a/internal/merch/repository_prices.go b/internal/merch/repository_prices.go index a9310d0..b981443 100644 --- a/internal/merch/repository_prices.go +++ b/internal/merch/repository_prices.go @@ -14,7 +14,7 @@ type Prices interface { getZeroPrices(ctx context.Context, userId int64) ([]ZeroPrice, error) deleteZeroPricesPeriod(ctx context.Context, userId int64, start, end time.Time, now sql.NullTime) error - deleteZeroPrices(ctx context.Context, now sql.NullTime, list []int64) error + deleteZeroPrices(ctx context.Context, userId int64, now sql.NullTime, list []int64) error } func (r *repo) insertPrices(ctx context.Context, prices []Price) error { @@ -192,10 +192,17 @@ func (r *repo) deleteZeroPricesPeriod(ctx context.Context, userId int64, start, return nil } -func (r *repo) deleteZeroPrices(ctx context.Context, now sql.NullTime, list []int64) error { - q := `UPDATE merch_prices SET deleted_at = $1 WHERE id IN $2` +func (r *repo) deleteZeroPrices(ctx context.Context, userId int64, now sql.NullTime, list []int64) error { + q := ` + UPDATE merch_prices mp + SET deleted_at = $1 + FROM merch m + WHERE mp.id = ANY($2) + AND mp.merch_id = m.id + AND m.user_id = $3 + ` - _, err := r.db.Exec(ctx, q, now, list) + _, err := r.db.Exec(ctx, q, now, list, userId) if err != nil { return err } diff --git a/internal/merch/service_prices.go b/internal/merch/service_prices.go index 07547f0..067326f 100644 --- a/internal/merch/service_prices.go +++ b/internal/merch/service_prices.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "time" ) func (s *service) getPrices(ctx context.Context, userId int64, days int) ([]PricesResponse, error) { @@ -123,3 +124,19 @@ func (s *service) getDistinctPrices(ctx context.Context, userId int64, merchUuid return &response, nil } + +func (s *service) getZeroPrices(ctx context.Context, userId int64) ([]ZeroPrice, error) { + return s.repo.getZeroPrices(ctx, userId) +} + +func (s *service) deleteZeroPricesPeriod(ctx context.Context, userId int64, start, end time.Time) error { + return s.repo.deleteZeroPricesPeriod(ctx, userId, start, end, s.utils.NullTimeNowUTC()) +} + +func (s *service) deleteZeroPrices(ctx context.Context, userId int64, list []DeleteZeroPrices) error { + var l []int64 + for _, item := range list { + l = append(l, item.Id) + } + return s.repo.deleteZeroPrices(ctx, userId, s.utils.NullTimeNowUTC(), l) +}