backend/api/restock.go

Summary

Maintainability
B
5 hrs
Test Coverage
package api

import (
    "bar/autogen"
    "bar/internal/models"
    "math"
    "time"

    "github.com/google/uuid"
    "github.com/labstack/echo/v4"
    "github.com/sirupsen/logrus"
    "go.mongodb.org/mongo-driver/mongo"
)

func arrondiAuMutilple(x uint64, a uint64) uint64 {
    return ((x + a/2) / a) * a
}

// (GET /restocks)
func (s *Server) GetRestocks(c echo.Context, params autogen.GetRestocksParams) error {
    _, err := MustGetAdmin(c)
    if err != nil {
        return nil
    }

    count, err := s.DBackend.CountAllRestocks(c.Request().Context())
    if err != nil {
        logrus.Error(err)
        return Error500(c)
    }

    // Make sure the last page is not empty
    dbpage, page, limit, maxPage := autogen.Pager(params.Page, params.Limit, &count)

    data, err := s.DBackend.GetAllRestocks(c.Request().Context(), dbpage, limit)
    if err != nil {
        logrus.Error(err)
        return Error500(c)
    }

    restocks := make([]autogen.Restock, len(data))
    for i, r := range data {
        restocks[i] = r.Restock
    }

    autogen.GetRestocks200JSONResponse{
        Restocks: restocks,
        Limit:    limit,
        Page:     page,
        MaxPage:  maxPage,
    }.VisitGetRestocksResponse(c.Response())
    return nil
}

// (POST /restocks)
func (s *Server) CreateRestock(c echo.Context) error {
    usr, err := MustGetAdmin(c)
    if err != nil {
        return nil
    }

    var body autogen.CreateRestockJSONRequestBody
    if err := c.Bind(&body); err != nil {
        logrus.Error(err)
        return Error400(c)
    }

    restock := models.Restock{
        Restock: autogen.Restock{
            DriverId:      body.DriverId,
            Id:            uuid.New(),
            TotalCostHt:   body.TotalCostHt,
            TotalCostTtc:  body.TotalCostTtc,
            Type:          body.Type,
            CreatedAt:     uint64(time.Now().Unix()),
            CreatedBy:     usr.Id,
            CreatedByName: usr.Name(),
        },
        CreatedAt: time.Now().Unix(),
    }

    _, err = s.DBackend.WithTransaction(c.Request().Context(), func(ctx mongo.SessionContext) (interface{}, error) {
        for _, item := range body.Items {
            restockItem := autogen.RestockItem{
                AmountOfBundle:  item.AmountOfBundle,
                AmountPerBundle: item.AmountPerBundle,
                BundleCostHt:    item.BundleCostHt,
                BundleCostTtc:   item.BundleCostTtc,
                ItemId:          item.ItemId,
                Tva:             item.Tva,
            }

            // Get item to check if it exists
            item, err := s.DBackend.GetItem(c.Request().Context(), item.ItemId.String())
            if err != nil {
                if err == mongo.ErrNoDocuments {
                    return nil, ErrorItemNotFound(c)
                }
                logrus.Error(err)
                return nil, Error500(c)
            }

            restockItem.ItemName = item.Name
            restockItem.ItemPictureUri = item.PictureUri
            item.State = autogen.ItemBuyable
            item.AmountLeft += restockItem.AmountOfBundle * restockItem.AmountPerBundle
            item.LastTva = &restockItem.Tva
            item.Prices.Coutant = uint64(math.Ceil(float64(restockItem.BundleCostTtc) / (float64(restockItem.AmountPerBundle))))
            if item.Prices.Coutant < 30 {
                item.Prices.Externe = arrondiAuMutilple(item.Prices.Coutant, 5) + 20
                item.Prices.Ceten = arrondiAuMutilple(item.Prices.Coutant, 5) + 10
                item.Prices.StaffBar = arrondiAuMutilple(item.Prices.Coutant, 5) + 5
                item.Prices.Privilegies = arrondiAuMutilple(item.Prices.Coutant, 5) + 5
                item.Prices.Menu = arrondiAuMutilple(item.Prices.Coutant, 5) + 10
            } else if item.Prices.Coutant >= 30 && item.Prices.Coutant < 130 {
                item.Prices.Externe = arrondiAuMutilple(item.Prices.Coutant*3/2, 5)
                item.Prices.Ceten = arrondiAuMutilple(item.Prices.Coutant*113/100, 5)
                item.Prices.StaffBar = arrondiAuMutilple(item.Prices.Coutant*108/100, 5)
                item.Prices.Privilegies = arrondiAuMutilple(item.Prices.Coutant*11/10, 5)
                item.Prices.Menu = arrondiAuMutilple(item.Prices.Coutant*13/10, 5)
            } else if item.Prices.Coutant >= 130 && item.Prices.Coutant < 300 {
                item.Prices.Externe = arrondiAuMutilple(item.Prices.Coutant*14/10, 5)
                item.Prices.Ceten = arrondiAuMutilple(item.Prices.Coutant*11/10, 5)
                item.Prices.StaffBar = arrondiAuMutilple(item.Prices.Coutant*108/100, 5)
                item.Prices.Privilegies = arrondiAuMutilple(item.Prices.Coutant*11/10, 5)
                item.Prices.Menu = arrondiAuMutilple(item.Prices.Coutant*12/10, 5)
            } else if item.Prices.Coutant >= 300 {
                item.Prices.Externe = arrondiAuMutilple(item.Prices.Coutant*125/100, 5)
                item.Prices.Ceten = arrondiAuMutilple(item.Prices.Coutant*11/10, 5)
                item.Prices.StaffBar = arrondiAuMutilple(item.Prices.Coutant*105/100, 5)
                item.Prices.Privilegies = arrondiAuMutilple(item.Prices.Coutant*11/10, 5)
                item.Prices.Menu = arrondiAuMutilple(item.Prices.Coutant*1125/1000, 5)
            }
            err = s.DBackend.UpdateItem(c.Request().Context(), item)
            if err != nil {
                logrus.Error(err)
                return nil, Error500(c)
            }

            restock.Items = append(restock.Items, restockItem)
        }

        err = s.DBackend.CreateRestock(c.Request().Context(), &restock)
        if err != nil {
            logrus.Error(err)
            return nil, Error500(c)
        }

        return nil, nil
    })
    if err != nil {
        logrus.Error(err)
        return nil
    }
    logrus.WithField("restock", restock.Id.String()).WithField("by", usr.Name()).Info("Created restock")
    if c.Response().Committed {
        return nil
    }

    autogen.CreateRestock201JSONResponse(restock.Restock).VisitCreateRestockResponse(c.Response())
    return nil
}

// (DELETE /restocks/{restock_id})
func (s *Server) DeleteRestock(c echo.Context, restockId autogen.UUID) error {
    account, err := MustGetAdmin(c)
    if err != nil {
        return nil
    }

    _, err = s.DBackend.WithTransaction(c.Request().Context(), func(ctx mongo.SessionContext) (interface{}, error) {
        // Remove restock from all items
        restock, err := s.DBackend.GetRestock(c.Request().Context(), restockId.String())
        if err != nil {
            if err == mongo.ErrNoDocuments {
                return nil, ErrorRestockNotFound(c)
            }
            logrus.Error(err)
            return nil, Error500(c)
        }

        for _, item := range restock.Items {
            i, err := s.DBackend.GetItem(c.Request().Context(), item.ItemId.String())
            if err != nil {
                if err == mongo.ErrNoDocuments {
                    return nil, ErrorItemNotFound(c)
                }
                logrus.Error(err)
                return nil, Error500(c)
            }

            i.AmountLeft -= item.AmountOfBundle * item.AmountPerBundle

            err = s.DBackend.UpdateItem(c.Request().Context(), i)
            if err != nil {
                logrus.Error(err)
                return nil, Error500(c)
            }
        }

        // Get restock from database
        err = s.DBackend.MarkDeleteRestock(c.Request().Context(), restockId.String(), account.Id.String())
        if err != nil {
            if err == mongo.ErrNoDocuments {
                return nil, ErrorRestockNotFound(c)
            }
            logrus.Error(err)
            return nil, Error500(c)
        }
        return nil, nil
    })
    if err != nil {
        logrus.Error(err)
        return nil
    }

    if c.Response().Committed {
        return nil
    }

    logrus.WithField("restock", restockId.String()).WithField("by", account.Name()).Info("Restock marked for deletion")
    autogen.DeleteRestock204Response{}.VisitDeleteRestockResponse(c.Response())
    return nil
}