backend/api/refills.go

Summary

Maintainability
A
0 mins
Test Coverage
package api

import (
    "bar/autogen"
    "bar/internal/models"
    "errors"
    "fmt"
    "math"
    "strconv"
    "time"

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

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

    var startsAt uint64 = 0
    if params.StartDate != nil {
        startsAt, _ = strconv.ParseUint(*params.StartDate, 10, 64)
    }
    var endsAt uint64 = math.MaxInt64
    if params.EndDate != nil {
        endsAt, _ = strconv.ParseUint(*params.EndDate, 10, 64)
    }

    count, err := s.DBackend.CountAllRefills(c.Request().Context(), startsAt, endsAt)
    if err != nil {
        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.GetAllRefills(c.Request().Context(), dbpage, limit, startsAt, endsAt)
    if err != nil {
        return Error500(c)
    }

    var refills []autogen.Refill

    for _, refill := range data {
        refills = append(refills, refill.Refill)
    }

    autogen.GetRefills200JSONResponse{
        Refills: refills,
        Limit:   limit,
        Page:    page,
        MaxPage: maxPage,
    }.VisitGetRefillsResponse(c.Response())
    return nil
}

// (GET /account/refills)
func (s *Server) GetSelfRefills(c echo.Context, params autogen.GetSelfRefillsParams) error {
    // Get account from cookie
    _, err := MustGetUser(c)
    if err != nil {
        return nil
    }

    accountID := c.Get("userAccountID").(string)

    var startsAt uint64 = 0
    if params.StartDate != nil {
        startsAt = uint64(params.StartDate.Unix())
    }

    var endsAt uint64 = math.MaxInt64
    if params.EndDate != nil {
        endsAt = uint64(params.EndDate.Unix())
    }

    count, err := s.DBackend.CountRefills(c.Request().Context(), accountID, startsAt, endsAt)
    if err != nil {
        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.GetRefills(c.Request().Context(), accountID, dbpage, limit, startsAt, endsAt)
    if err != nil {
        return Error500(c)
    }

    var refills []autogen.Refill

    for _, refill := range data {
        refills = append(refills, refill.Refill)
    }

    autogen.GetSelfRefills200JSONResponse{
        Refills: refills,
        Limit:   limit,
        Page:    page,
        MaxPage: maxPage,
    }.VisitGetSelfRefillsResponse(c.Response())
    return nil
}

// (GET /accounts/{account_id}/refills)
func (s *Server) GetAccountRefills(c echo.Context, accountId string, params autogen.GetAccountRefillsParams) error {
    _, err := MustGetAdmin(c)
    if err != nil {
        return nil
    }

    account, err := s.DBackend.GetAccountByCard(c.Request().Context(), accountId)
    if account == nil {
        account, err = s.DBackend.GetAccount(c.Request().Context(), accountId)
    }
    if err != nil {
        if err == mongo.ErrNoDocuments {
            return ErrorAccNotFound(c)
        }
        return Error500(c)
    }

    var startsAt uint64 = 0
    if params.StartDate != nil {
        startsAt = uint64(params.StartDate.Unix())
    }

    var endsAt uint64 = math.MaxInt64
    if params.EndDate != nil {
        endsAt = uint64(params.EndDate.Unix())
    }

    count, err := s.DBackend.CountRefills(c.Request().Context(), account.Id.String(), startsAt, endsAt)
    if err != nil {
        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.GetRefills(c.Request().Context(), account.Id.String(), dbpage, limit, startsAt, endsAt)
    if err != nil {
        return Error500(c)
    }

    var refills []autogen.Refill

    for _, refill := range data {
        refills = append(refills, refill.Refill)
    }

    autogen.GetAccountRefills200JSONResponse{
        Refills: refills,
        Limit:   limit,
        Page:    page,
        MaxPage: maxPage,
    }.VisitGetAccountRefillsResponse(c.Response())
    return nil
}

// (POST /accounts/{account_id}/refills)
func (s *Server) PostRefill(c echo.Context, accountId string, params autogen.PostRefillParams) error {
    admin, err := MustGetAdmin(c)
    if err != nil {
        return nil
    }

    account, err := s.DBackend.GetAccountByCard(c.Request().Context(), accountId)
    if account == nil {
        account, err = s.DBackend.GetAccount(c.Request().Context(), accountId)
    }
    if err != nil {
        if err == mongo.ErrNoDocuments {
            return ErrorAccNotFound(c)
        }
        return Error500(c)
    }

    refill := &models.Refill{
        Refill: autogen.Refill{
            AccountId:    account.Id,
            AccountName:  account.Name(),
            Amount:       params.Amount,
            Type:         params.Type,
            Id:           uuid.New(),
            IssuedAt:     uint64(time.Now().Unix()),
            IssuedBy:     admin.Id,
            IssuedByName: admin.Name(),
            State:        autogen.Valid,
        },
    }

    account.Balance += int64(params.Amount)

    _, err = s.DBackend.WithTransaction(c.Request().Context(), func(ctx mongo.SessionContext) (interface{}, error) {
        err := s.DBackend.CreateRefill(ctx, refill)
        if err != nil {
            return nil, errors.New("failed to create refill")
        }

        err = s.DBackend.UpdateAccount(ctx, account)
        if err != nil {
            return nil, errors.New("failed to update account")
        }

        if params.Type == autogen.RefillCash {
            err = s.createCashMovement(ctx, admin.Id, admin.Name(), int64(params.Amount), fmt.Sprintf("Recharge %s", refill.Id))
            if err != nil {
                return nil, errors.New("failed to create cash movement")
            }
        }

        return nil, nil
    })
    if err != nil {
        return Error500(c)
    }

    logrus.WithField("refill", refill.Id.String()).WithField("account", account.Name()).Info("Refill created")
    autogen.PostRefill201JSONResponse(refill.Refill).VisitPostRefillResponse(c.Response())
    return nil
}

// (PATCH /accounts/{account_id}/refills/{refill_id})
func (s *Server) PatchRefillId(c echo.Context, accountId autogen.UUID, refillId autogen.UUID, params autogen.PatchRefillIdParams) error {
    admin, err := MustGetAdmin(c)
    if err != nil {
        return nil
    }

    account, err := s.DBackend.GetAccount(c.Request().Context(), accountId.String())
    if err != nil {
        if err == mongo.ErrNoDocuments {
            return ErrorAccNotFound(c)
        }
        return Error500(c)
    }

    refill, err := s.DBackend.GetRefill(c.Request().Context(), refillId.String())
    if err != nil {
        if err == mongo.ErrNoDocuments {
            return ErrorRefillNotFound(c)
        }
        return Error500(c)
    }

    _, err = s.DBackend.WithTransaction(c.Request().Context(), func(ctx mongo.SessionContext) (interface{}, error) {
        if params.State != nil {
            oldState := refill.State
            refill.State = *params.State

            if oldState == autogen.Valid && *params.State == autogen.Canceled {
                account.Balance -= int64(refill.Amount)

                name := admin.Name()

                refill.CanceledBy = &admin.Id
                refill.CanceledByName = &name

                err = s.createCashMovement(ctx, admin.Id, admin.Name(), -int64(refill.Amount), fmt.Sprintf("Annulation de recharge %s", refill.Id))
                if err != nil {
                    return nil, errors.New("failed to create cash movement")
                }
            } else if oldState == autogen.Canceled && *params.State == autogen.Valid {
                account.Balance += int64(refill.Amount)
                refill.CanceledBy = nil
                refill.CanceledByName = nil

                err = s.createCashMovement(ctx, admin.Id, admin.Name(), int64(refill.Amount), fmt.Sprintf("Revalidation de recharge %s", refill.Id))
                if err != nil {
                    return nil, errors.New("failed to create cash movement")
                }
            }
        }

        if params.Type != nil {
            refill.Type = *params.Type
        }

        err := s.DBackend.UpdateRefill(ctx, refill)
        if err != nil {
            return nil, errors.New("failed to update refill")
        }

        err = s.DBackend.UpdateAccount(ctx, account)
        if err != nil {
            return nil, errors.New("failed to update account")
        }

        return nil, nil
    })
    if err != nil {
        return Error500(c)
    }

    logrus.WithField("refill", refill.Id.String()).WithField("account", account.Name()).Info("Refill updated")
    autogen.PatchRefillId200JSONResponse(refill.Refill).VisitPatchRefillIdResponse(c.Response())
    return nil
}

// (DELETE /accounts/{account_id}/refills/{refill_id})
func (s *Server) MarkDeleteRefill(c echo.Context, accountId autogen.UUID, refillId autogen.UUID) error {
    account, err := MustGetAdmin(c)
    if err != nil {
        return nil
    }

    _, err = s.DBackend.GetRefill(c.Request().Context(), refillId.String())
    if err != nil {
        if err == mongo.ErrNoDocuments {
            return ErrorRefillNotFound(c)
        }
        return Error500(c)
    }

    err = s.DBackend.MarkDeleteRefill(c.Request().Context(), refillId.String(), account.Id.String())
    if err != nil {
        return Error500(c)
    }

    logrus.WithField("refill", refillId.String()).WithField("account", account.Name()).Info("Refill marked for deletion")
    autogen.MarkDeleteAccountId204Response{}.VisitMarkDeleteAccountIdResponse(c.Response())
    return nil
}