customer/internal/interface/controller/http/controllers.go

1026 lines
30 KiB
Go
Raw Normal View History

2024-05-20 12:32:59 +00:00
package http
2023-11-05 13:58:41 +00:00
import (
2023-11-06 08:30:41 +00:00
"fmt"
2024-02-16 19:28:20 +00:00
"github.com/gofiber/fiber/v2"
2023-11-06 12:02:13 +00:00
"math"
2024-02-01 13:48:29 +00:00
"os"
2024-04-26 15:49:40 +00:00
codeword_rpc "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/codeword"
2024-05-19 16:00:03 +00:00
"strconv"
2023-11-07 05:14:04 +00:00
"sync"
"time"
2023-11-06 08:30:41 +00:00
2023-11-05 13:58:41 +00:00
"go.mongodb.org/mongo-driver/mongo"
"go.uber.org/zap"
2023-11-07 05:14:04 +00:00
"google.golang.org/protobuf/types/known/timestamppb"
2024-04-15 09:27:00 +00:00
qutils "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/utils"
2023-11-06 08:30:41 +00:00
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
2023-11-07 05:14:04 +00:00
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/broker/tariff"
2023-11-06 10:30:07 +00:00
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client"
2023-11-05 13:58:41 +00:00
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository"
2023-11-06 08:30:41 +00:00
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
2023-11-07 05:14:04 +00:00
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/discount"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/history"
2023-11-06 12:02:13 +00:00
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils"
2023-11-07 05:14:04 +00:00
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils/transfer"
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate"
2023-11-05 13:58:41 +00:00
)
2023-11-06 10:30:07 +00:00
const defaultCurrency = "RUB" // TODO move
2023-11-05 13:58:41 +00:00
type API2 struct {
2023-11-06 07:27:06 +00:00
logger *zap.Logger
history repository.HistoryRepository
account repository.AccountRepository
currency repository.CurrencyRepository
2023-11-07 05:14:04 +00:00
producer *tariff.Producer
consumer *tariff.Consumer
clients clients
2023-11-07 08:13:22 +00:00
grpc models.ConfigurationGRPC
2024-04-15 09:27:00 +00:00
encrypt *qutils.Encrypt
2023-11-07 05:14:04 +00:00
}
type clients struct {
2023-11-06 10:30:07 +00:00
auth *client.AuthClient
2023-11-07 05:14:04 +00:00
hubadmin *client.HubadminClient
currency *client.CurrencyClient
2023-11-07 08:13:22 +00:00
discount *client.DiscountClient
payment *client.PaymentClient
2024-02-01 13:48:29 +00:00
verify *client.VerificationClient
template *client.TemplateClient
2024-02-05 12:24:56 +00:00
mail *client.MailClient
2024-04-25 12:53:33 +00:00
codeword *client.CodewordClient
2023-11-05 13:58:41 +00:00
}
2024-05-20 12:32:59 +00:00
func NewAPI2(logger *zap.Logger, db *mongo.Database, config *models.Config, consumer *tariff.Consumer, producer *tariff.Producer, encrypt *qutils.Encrypt) *API2 {
return &API2{
2023-11-06 07:27:06 +00:00
logger: logger,
history: repository.NewHistoryRepository2(logger, db.Collection("histories")),
currency: repository.NewCurrencyRepository2(logger, db.Collection("currency_lists")),
account: repository.NewAccountRepository2(logger, db.Collection("accounts")),
2023-11-07 05:14:04 +00:00
consumer: consumer,
producer: producer,
2024-04-24 12:20:21 +00:00
encrypt: encrypt,
2023-11-07 08:13:22 +00:00
grpc: config.GRPC,
2023-11-07 05:14:04 +00:00
clients: clients{
auth: client.NewAuthClient(client.AuthClientDeps{Logger: logger, URLs: &config.Service.AuthMicroservice.URL}),
hubadmin: client.NewHubadminClient(client.HubadminClientDeps{Logger: logger, URLs: &config.Service.HubadminMicroservice.URL}),
currency: client.NewCurrencyClient(client.CurrencyClientDeps{Logger: logger, URLs: &config.Service.CurrencyMicroservice.URL}),
2023-11-07 08:13:22 +00:00
discount: client.NewDiscountClient(client.DiscountClientDeps{Logger: logger, DiscountServiceHost: config.Service.DiscountMicroservice.HostGRPC}),
payment: client.NewPaymentClient(client.PaymentClientDeps{Logger: logger, PaymentServiceHost: config.Service.PaymentMicroservice.HostGRPC}),
2024-02-16 19:28:20 +00:00
verify: client.NewVerificationClient(client.VerificationClientDeps{Logger: logger, URLs: &config.Service.VerificationMicroservice.URL}),
template: client.NewTemplateClient(client.TemplateClientDeps{Logger: logger, URLs: &config.Service.TemplategenMicroserviceURL.URL}),
mail: client.NewMailClient(client.MailClientDeps{Logger: logger,
ApiUrl: config.Service.Mail.ApiUrl,
Sender: config.Service.Mail.Sender,
Auth: &models.PlainAuth{
Identity: config.Service.Mail.Auth.Identity,
Username: config.Service.Mail.Auth.Username,
Password: config.Service.Mail.Auth.Password,
},
ApiKey: config.Service.Mail.ApiKey,
FiberClient: fiber.AcquireClient(),
MailAddress: config.Service.Mail.MailAddress,
}),
2024-04-25 12:53:33 +00:00
codeword: client.NewCodewordClient(client.CodewordClientDeps{Logger: logger, CodewordServiceHost: config.Service.CodewordMicroservice.HostGRPC}),
2023-11-07 05:14:04 +00:00
},
2023-11-05 13:58:41 +00:00
}
}
2024-05-19 16:00:03 +00:00
func (api *API2) error(ctx *fiber.Ctx, status int, message string, rest ...any) error {
2023-11-08 04:40:38 +00:00
if len(rest) > 0 {
message = fmt.Sprintf(message, rest...)
}
api.logger.Error(message)
2024-05-19 16:00:03 +00:00
return ctx.Status(status).JSON(models.ResponseErrorHTTP{
2023-11-08 04:40:38 +00:00
StatusCode: status,
Message: message,
})
}
2024-05-19 16:00:03 +00:00
func (api *API2) errorOld(ctx *fiber.Ctx, err error) error {
2023-11-08 07:04:18 +00:00
api.logger.Error("error:", zap.Error(err))
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusInternalServerError).JSON(models.ResponseErrorHTTP{
StatusCode: fiber.StatusInternalServerError,
Message: err.Error(),
})
2023-11-08 07:04:18 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) noauth(ctx *fiber.Ctx) error {
return api.error(ctx, fiber.StatusUnauthorized, "failed to get jwt payload")
2023-11-08 06:06:19 +00:00
}
2024-05-20 14:29:45 +00:00
func (api *API2) extractUserID(ctx *fiber.Ctx) (string, bool) {
id, ok := ctx.Context().UserValue(models.AuthJWTDecodedUserIDKey).(string)
return id, ok
}
func (api *API2) extractToken(ctx *fiber.Ctx) (string, bool) {
token, ok := ctx.Context().UserValue(models.AuthJWTDecodedAccessTokenKey).(string)
return token, ok
}
2023-11-06 08:30:41 +00:00
// Health
2024-05-19 16:00:03 +00:00
func (api *API2) GetHealth(ctx *fiber.Ctx) error {
return ctx.Status(fiber.StatusOK).SendString("OK")
2023-11-05 13:58:41 +00:00
}
2023-11-06 08:30:41 +00:00
// Account
2024-05-19 16:00:03 +00:00
func (api *API2) DeleteAccount(ctx *fiber.Ctx) error {
2024-05-20 14:29:45 +00:00
userID, ok := api.extractUserID(ctx)
if !ok || userID == "" {
2023-11-08 06:06:19 +00:00
return api.noauth(ctx)
2023-11-06 09:31:39 +00:00
}
2024-05-19 16:00:03 +00:00
account, err := api.account.Remove(ctx.Context(), userID)
2023-11-06 09:31:39 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-06 09:31:39 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(account)
2023-11-05 13:58:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) ChangeAccount(ctx *fiber.Ctx) error {
2024-05-20 14:29:45 +00:00
userID, ok := api.extractUserID(ctx)
if !ok || userID == "" {
2023-11-08 06:06:19 +00:00
return api.noauth(ctx)
2023-11-06 08:30:41 +00:00
}
2024-05-19 16:00:03 +00:00
var request models.Name
if err := ctx.BodyParser(&request); err != nil {
return api.error(ctx, fiber.StatusBadRequest, "failed to bind json", err)
2023-11-06 08:30:41 +00:00
}
2024-05-19 16:00:03 +00:00
account, err := api.account.UpdateName(ctx.Context(), userID, &request)
2023-11-06 08:30:41 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-06 08:30:41 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(account)
2023-11-05 13:58:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) SetAccountVerificationStatus(ctx *fiber.Ctx) error {
userID := ctx.Params("userId")
if userID == "" {
return api.error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId")
}
2024-05-20 14:29:45 +00:00
2024-05-19 16:00:03 +00:00
var request models.SetAccountStatus
if err := ctx.BodyParser(&request); err != nil {
return api.error(ctx, fiber.StatusBadRequest, "failed to bind json", err)
2023-11-06 08:30:41 +00:00
}
2024-05-19 16:00:03 +00:00
account, err := api.account.SetStatus(ctx.Context(), userID, request.Status)
2023-11-06 08:30:41 +00:00
if err != nil {
api.logger.Error("failed to set status on <SetVerificationStatus> of <AccountService>", zap.Error(err))
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-06 08:30:41 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(account)
2023-11-05 13:58:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) GetAccount(ctx *fiber.Ctx) error {
2024-05-20 14:29:45 +00:00
userID, ok := api.extractUserID(ctx)
if !ok || userID == "" {
2023-11-08 06:06:19 +00:00
return api.noauth(ctx)
2023-11-06 10:30:07 +00:00
}
2024-05-19 16:00:03 +00:00
account, err := api.account.FindByUserID(ctx.Context(), userID)
2023-11-06 10:30:07 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-06 10:30:07 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(account)
2023-11-05 13:58:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) AddAccount(ctx *fiber.Ctx) error {
2024-05-20 14:29:45 +00:00
userID, ok := api.extractUserID(ctx)
if !ok || userID == "" {
2023-11-08 06:06:19 +00:00
return api.noauth(ctx)
2023-11-06 10:30:07 +00:00
}
2024-03-23 10:06:39 +00:00
2024-05-19 16:00:03 +00:00
var er error
2024-05-19 16:00:03 +00:00
quizFrom := ctx.Cookies("quizFrom")
quizUser := ctx.Cookies("quizUser")
if quizUser != "" {
quizUser, er = api.encrypt.DecryptStr([]byte(quizUser))
if er != nil {
return api.errorOld(ctx, er)
}
}
2023-11-06 10:30:07 +00:00
2024-05-19 16:00:03 +00:00
account, err := api.account.FindByUserID(ctx.Context(), userID)
2023-11-06 10:30:07 +00:00
if err != nil && err.Type() != errors.ErrNotFound {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-06 10:30:07 +00:00
}
if account != nil {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusBadRequest, "account exists")
2023-11-06 10:30:07 +00:00
}
2024-05-19 16:00:03 +00:00
user, err := api.clients.auth.GetUser(ctx.Context(), userID)
2023-11-06 10:30:07 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-06 10:30:07 +00:00
}
2024-05-19 16:00:03 +00:00
account, err = api.account.Insert(ctx.Context(), &models.Account{
UserID: user.ID, Wallet: models.Wallet{Currency: defaultCurrency}, From: quizFrom, Partner: quizUser})
2023-11-06 10:30:07 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-06 10:30:07 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(account)
2023-11-05 13:58:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) DeleteDirectAccount(ctx *fiber.Ctx) error {
userID := ctx.Params("userId")
if userID == "" {
return api.error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId")
}
account, err := api.account.Remove(ctx.Context(), userID)
2023-11-06 11:51:55 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-06 11:51:55 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(account)
2023-11-06 08:30:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) GetDirectAccount(ctx *fiber.Ctx) error {
userID := ctx.Params("userId")
if userID == "" {
return api.error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId")
}
account, err := api.account.FindByUserID(ctx.Context(), userID)
2023-11-06 11:54:15 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-06 11:54:15 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(account)
2023-11-05 13:58:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) PaginationAccounts(ctx *fiber.Ctx) error {
pageStr := ctx.Query("page", "1")
limitStr := ctx.Query("limit", "100")
2023-11-06 12:02:13 +00:00
2024-05-19 16:00:03 +00:00
page, err := strconv.ParseInt(pageStr, 10, 64)
if err != nil || page < 1 {
page = 1
}
limit, err := strconv.ParseInt(limitStr, 10, 64)
if err != nil || limit < 1 {
limit = models.DefaultLimit
} else {
limit = int64(math.Min(float64(limit), float64(models.DefaultLimit)))
}
2023-11-08 05:52:47 +00:00
2024-05-19 16:00:03 +00:00
count, err := api.account.CountAll(ctx.Context())
2023-11-06 12:02:13 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-06 12:02:13 +00:00
}
if count == 0 {
response := models.PaginationResponse[models.Account]{TotalPages: 0, Records: []models.Account{}}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(response)
2023-11-06 12:02:13 +00:00
}
2023-11-08 05:52:47 +00:00
totalPages := int64(math.Ceil(float64(count) / float64(limit)))
2023-11-06 12:02:13 +00:00
2024-05-19 16:00:03 +00:00
accounts, err := api.account.FindMany(ctx.Context(), page, limit)
2023-11-06 12:02:13 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-06 12:02:13 +00:00
}
response := models.PaginationResponse[models.Account]{
TotalPages: totalPages,
Records: accounts,
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(response)
2023-11-05 13:58:41 +00:00
}
2023-11-06 08:30:41 +00:00
// Cart
2024-05-19 16:00:03 +00:00
func (api *API2) RemoveFromCart(ctx *fiber.Ctx) error {
2024-05-20 14:29:45 +00:00
userID, ok := api.extractUserID(ctx)
if !ok || userID == "" {
2023-11-08 06:06:19 +00:00
return api.noauth(ctx)
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
id := ctx.Query("id")
if id == "" {
return api.error(ctx, fiber.StatusBadRequest, "empty item id")
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
cartItems, err := api.account.RemoveItemFromCart(ctx.Context(), userID, id)
2023-11-07 05:14:04 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(cartItems)
2023-11-05 13:58:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) Add2cart(ctx *fiber.Ctx) error {
2024-05-20 14:29:45 +00:00
userID, ok := api.extractUserID(ctx)
if !ok || userID == "" {
2023-11-08 06:06:19 +00:00
return api.noauth(ctx)
2023-11-07 05:14:04 +00:00
}
2024-05-20 14:29:45 +00:00
token, ok := api.extractToken(ctx)
if !ok || token == "" {
2023-11-08 06:06:19 +00:00
return api.noauth(ctx)
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
tariffID := ctx.Query("id")
if tariffID == "" {
return api.error(ctx, fiber.StatusBadRequest, "empty item id")
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
tariff, err := api.clients.hubadmin.GetTariff(ctx.Context(), token, tariffID)
2023-11-07 05:14:04 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
if tariff == nil {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusNotFound, "tariff not found")
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
cartItems, err := api.account.AddItemToCart(ctx.Context(), userID, tariffID)
2023-11-07 05:14:04 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(cartItems)
2023-11-05 13:58:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) PayCart(ctx *fiber.Ctx) error {
2024-05-20 14:29:45 +00:00
userID, ok := api.extractUserID(ctx)
if !ok || userID == "" {
2023-11-08 06:06:19 +00:00
return api.noauth(ctx)
2023-11-07 05:14:04 +00:00
}
2024-05-20 14:29:45 +00:00
accessToken, ok := api.extractToken(ctx)
if !ok || accessToken == "" {
2023-11-08 06:06:19 +00:00
return api.noauth(ctx)
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
account, err := api.account.FindByUserID(ctx.Context(), userID)
2023-11-07 05:14:04 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
api.logger.Info("account for pay", zap.Any("acc", account))
2024-05-19 16:00:03 +00:00
tariffs, err := api.clients.hubadmin.GetTariffs(ctx.Context(), accessToken, account.Cart)
2023-11-07 05:14:04 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
api.logger.Info("tariffs for pay", zap.Any("acc", tariffs))
tariffsAmount := utils.CalculateCartPurchasesAmount(tariffs)
2024-05-19 16:00:03 +00:00
discountResponse, err := api.clients.discount.Apply(ctx.Context(), &discount.ApplyDiscountRequest{
2023-11-07 05:14:04 +00:00
UserInformation: &discount.UserInformation{
ID: account.UserID,
Type: string(account.Status),
2024-04-09 18:56:58 +00:00
PurchasesAmount: uint64(account.Wallet.Spent),
2023-11-07 05:14:04 +00:00
CartPurchasesAmount: tariffsAmount,
},
Products: transfer.TariffsToProductInformations(tariffs),
Date: timestamppb.New(time.Now()),
})
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
api.logger.Info("discountResponse for pay", zap.Any("acc", discount.ApplyDiscountRequest{
UserInformation: &discount.UserInformation{
ID: account.UserID,
Type: string(account.Status),
2024-02-01 09:39:34 +00:00
PurchasesAmount: uint64(account.Wallet.Spent),
2023-11-07 05:14:04 +00:00
CartPurchasesAmount: tariffsAmount,
},
Products: transfer.TariffsToProductInformations(tariffs),
Date: timestamppb.New(time.Now()),
}))
if account.Wallet.Money < int64(discountResponse.Price) {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusPaymentRequired, "insufficient funds: %d", int64(discountResponse.Price)-account.Wallet.Money)
2023-11-07 05:14:04 +00:00
}
for _, applied := range discountResponse.AppliedDiscounts {
if applied.Condition.User != nil && *applied.Condition.User != "" {
2024-05-19 16:00:03 +00:00
_, err := api.clients.discount.DeleteDiscount(ctx.Context(), &discount.GetDiscountByIDRequest{
ID: applied.ID,
})
if err != nil {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusInternalServerError, "failed delete discount by id:%s", applied.ID)
}
}
}
2023-11-07 05:14:04 +00:00
// WithdrawAccountWalletMoney
request := models.WithdrawAccountWallet{
Money: int64(discountResponse.Price),
Account: account,
}
if validate.IsStringEmpty(request.Account.Wallet.Currency) {
request.Account.Wallet.Currency = models.InternalCurrencyKey
}
var updatedAccount *models.Account
if request.Account.Wallet.Currency == models.InternalCurrencyKey {
2024-05-19 16:00:03 +00:00
accountx, err := api.account.ChangeWallet(ctx.Context(), request.Account.UserID, &models.Wallet{
2023-11-07 05:14:04 +00:00
Cash: request.Account.Wallet.Cash - request.Money,
Money: request.Account.Wallet.Money - request.Money,
Spent: request.Account.Wallet.Spent + request.Money,
PurchasesAmount: request.Account.Wallet.PurchasesAmount,
Currency: request.Account.Wallet.Currency,
})
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
2023-11-07 08:13:22 +00:00
updatedAccount = accountx
2023-11-07 05:14:04 +00:00
} else {
2024-05-19 16:00:03 +00:00
cash, err := api.clients.currency.Translate(ctx.Context(), &models.TranslateCurrency{
2023-11-07 05:14:04 +00:00
Money: request.Money,
From: models.InternalCurrencyKey,
To: request.Account.Wallet.Currency,
})
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
accountx, err := api.account.ChangeWallet(ctx.Context(), request.Account.UserID, &models.Wallet{
2023-11-07 05:14:04 +00:00
Cash: request.Account.Wallet.Cash - cash,
Money: request.Account.Wallet.Money - request.Money,
Spent: request.Account.Wallet.Spent + request.Money,
PurchasesAmount: request.Account.Wallet.PurchasesAmount,
Currency: request.Account.Wallet.Currency,
})
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
2023-11-07 08:13:22 +00:00
updatedAccount = accountx
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
if _, err := api.history.Insert(ctx.Context(), &models.History{
2024-03-11 17:21:32 +00:00
Key: models.CustomerHistoryKeyPayCart,
UserID: account.UserID,
Comment: "Успешная оплата корзины",
2024-03-09 19:39:05 +00:00
RawDetails: models.RawDetails{
2024-03-11 17:21:32 +00:00
Tariffs: tariffs,
Price: int64(discountResponse.Price),
},
2023-11-07 05:14:04 +00:00
}); err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
// TODO: обработать ошибки при отправке сообщений
sendErrors := make([]errors.Error, 0)
waitGroup := sync.WaitGroup{}
2023-11-08 06:08:27 +00:00
mutex := sync.Mutex{}
2023-11-07 05:14:04 +00:00
for _, tariff := range tariffs {
waitGroup.Add(1)
go func(currentTariff models.Tariff) {
defer waitGroup.Done()
2024-05-19 16:00:03 +00:00
if err := api.producer.Send(ctx.Context(), userID, &currentTariff); err != nil {
2023-11-08 06:08:27 +00:00
mutex.Lock()
defer mutex.Unlock()
2023-11-07 05:14:04 +00:00
sendErrors = append(sendErrors, err)
}
}(tariff)
}
waitGroup.Wait()
if len(sendErrors) > 0 {
for _, err := range sendErrors {
api.logger.Error("failed to send tariffs to broker on <Pay> of <CartService>", zap.Error(err))
}
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusInternalServerError, "failed to send tariffs to broker")
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
if _, err := api.account.ClearCart(ctx.Context(), account.UserID); err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
updatedAccount.Cart = []string{}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(updatedAccount)
2023-11-05 13:58:41 +00:00
}
2023-11-06 08:30:41 +00:00
// Currency
2024-05-19 16:00:03 +00:00
func (api *API2) GetCurrencies(ctx *fiber.Ctx) error {
currencyList, err := api.currency.FindCurrenciesList(ctx.Context(), models.DefaultCurrencyListName)
2023-11-07 08:13:22 +00:00
if err != nil && err.Type() != errors.ErrNotFound {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 08:13:22 +00:00
}
if err != nil && err.Type() == errors.ErrNotFound {
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON([]string{})
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(currencyList)
2023-11-05 13:58:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) UpdateCurrencies(ctx *fiber.Ctx) error {
var req struct {
items []string
}
if err := ctx.BodyParser(&req); err != nil {
return api.error(ctx, fiber.StatusBadRequest, "failed to bind currencies")
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
currencies := req.items
2023-11-07 08:13:22 +00:00
2024-05-19 16:00:03 +00:00
currencyList, err := api.currency.ReplaceCurrencies(ctx.Context(), &models.CurrencyList{
2023-11-07 08:13:22 +00:00
Name: models.DefaultCurrencyListName,
Currencies: currencies,
})
if err != nil && err.Type() != errors.ErrNotFound {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 08:13:22 +00:00
}
if err != nil && err.Type() == errors.ErrNotFound {
2024-05-19 16:00:03 +00:00
newCurrencyList, err := api.currency.Insert(ctx.Context(), &models.CurrencyList{
2023-11-07 08:13:22 +00:00
Name: models.DefaultCurrencyListName,
Currencies: currencies,
})
if err != nil && err.Type() != errors.ErrNotFound {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(newCurrencyList.Currencies)
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(currencyList.Currencies)
2023-11-05 13:58:41 +00:00
}
2023-11-06 08:30:41 +00:00
// History
2024-05-19 16:00:03 +00:00
func (api *API2) GetHistory(ctx *fiber.Ctx) error {
var userID string
2024-05-19 16:00:03 +00:00
pageStr := ctx.Query("page")
limitStr := ctx.Query("limit")
tipe := ctx.Query("type")
accountID := ctx.Query("accountID")
if accountID != "" {
userID = accountID
} else {
2024-05-20 14:29:45 +00:00
id, ok := api.extractUserID(ctx)
if !ok || id == "" {
return api.noauth(ctx)
}
2024-05-20 14:31:37 +00:00
userID = id
2024-05-19 16:00:03 +00:00
}
limit, err := strconv.ParseInt(limitStr, 10, 64)
if err != nil {
return api.error(ctx, fiber.StatusBadRequest, "invalid limit format")
}
page, err := strconv.ParseInt(pageStr, 10, 64)
if err != nil {
return api.error(ctx, fiber.StatusBadRequest, "invalid page format")
}
2023-11-07 05:14:04 +00:00
dto := &history.GetHistories{
UserID: userID,
2024-05-19 16:00:03 +00:00
Type: &tipe,
2023-11-07 05:14:04 +00:00
Pagination: &models.Pagination{
2024-05-19 16:00:03 +00:00
Page: page,
Limit: limit,
2023-11-07 05:14:04 +00:00
},
}
2024-05-19 16:00:03 +00:00
count, err := api.history.CountAll(ctx.Context(), dto)
2023-11-07 05:14:04 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 05:14:04 +00:00
}
if count == 0 {
2023-11-08 06:41:25 +00:00
returnHistories := models.PaginationResponse[models.History]{TotalPages: 0, Records: []models.History{}}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(returnHistories)
2023-11-08 06:41:25 +00:00
}
2023-11-07 05:14:04 +00:00
2023-11-08 06:41:25 +00:00
totalPages := int64(math.Ceil(float64(count) / float64(dto.Pagination.Limit)))
2023-11-07 05:14:04 +00:00
2024-05-19 16:00:03 +00:00
histories, err := api.history.FindMany(ctx.Context(), dto)
2023-11-08 06:41:25 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-08 06:41:25 +00:00
}
returnHistories := models.PaginationResponse[models.History]{
TotalPages: totalPages,
Records: histories,
2023-11-07 05:14:04 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(returnHistories)
2023-11-05 13:58:41 +00:00
}
2023-11-06 08:30:41 +00:00
// Wallet
2023-11-05 13:58:41 +00:00
2024-05-19 16:00:03 +00:00
func (api *API2) RequestMoney(ctx *fiber.Ctx) error {
2024-05-20 14:29:45 +00:00
userID, ok := api.extractUserID(ctx)
if !ok || userID == "" {
2023-11-08 06:41:25 +00:00
return api.noauth(ctx)
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
var request models.GetPaymentLinkBody
if err := ctx.BodyParser(&request); err != nil {
return api.error(ctx, fiber.StatusBadRequest, "failed to bind payment link")
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
if err := utils.ValidateGetPaymentLinkBody(&request); err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
link, err := api.GetPaymentLink(ctx.Context(), &models.GetPaymentLinkRequest{
Body: &request,
2023-11-07 08:13:22 +00:00
UserID: userID,
2024-05-19 16:00:03 +00:00
ClientIP: ctx.IP(),
2023-11-07 08:13:22 +00:00
})
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(&models.GetPaymentLinkResponse{Link: link})
2023-11-06 08:30:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) ChangeCurrency(ctx *fiber.Ctx) error {
2024-05-20 14:29:45 +00:00
userID, ok := api.extractUserID(ctx)
if !ok || userID == "" {
2023-11-08 06:41:25 +00:00
return api.noauth(ctx)
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
var request models.ChangeCurrency
if err := ctx.BodyParser(&request); err != nil {
return api.error(ctx, fiber.StatusBadRequest, "failed to bind currency")
2023-11-07 08:13:22 +00:00
}
if validate.IsStringEmpty(request.Currency) {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusBadRequest, "empty currency")
2023-11-07 08:13:22 +00:00
}
currency := request.Currency
2024-05-19 16:00:03 +00:00
account, err := api.account.FindByUserID(ctx.Context(), userID)
2023-11-07 08:13:22 +00:00
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
cash, err := api.clients.currency.Translate(ctx.Context(), &models.TranslateCurrency{
2023-11-07 08:13:22 +00:00
Money: account.Wallet.Cash,
From: account.Wallet.Currency,
To: currency,
})
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
updatedAccount, err := api.account.ChangeWallet(ctx.Context(), account.UserID, &models.Wallet{
2023-11-07 08:13:22 +00:00
Cash: cash,
Currency: currency,
Money: account.Wallet.Money,
})
if err != nil {
2023-11-08 07:04:18 +00:00
return api.errorOld(ctx, err)
2023-11-07 08:13:22 +00:00
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(updatedAccount)
2023-11-05 13:58:41 +00:00
}
2023-11-05 13:58:41 +00:00
2024-05-19 16:00:03 +00:00
func (api *API2) CalculateLTV(ctx *fiber.Ctx) error {
var req struct {
From int64 `json:"from"`
To int64 `json:"to"`
}
2024-02-01 13:48:29 +00:00
2024-05-19 16:00:03 +00:00
if err := ctx.BodyParser(&req); err != nil {
2024-02-01 13:48:29 +00:00
api.logger.Error("failed to bind request", zap.Error(err))
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusBadRequest, "failed to bind request")
2024-02-01 13:48:29 +00:00
}
if req.From > req.To && req.To != 0 {
api.logger.Error("From timestamp must be less than To timestamp unless To is 0")
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusBadRequest, "From timestamp must be less than To timestamp unless To is 0")
2024-02-01 13:48:29 +00:00
}
2024-05-19 16:00:03 +00:00
ltv, err := api.history.CalculateCustomerLTV(ctx.Context(), req.From, req.To)
2024-02-01 13:48:29 +00:00
if err != nil {
api.logger.Error("failed to calculate LTV", zap.Error(err))
return api.errorOld(ctx, err)
}
response := struct {
LTV int64 `json:"LTV"`
}{
LTV: ltv,
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(response)
2023-11-05 13:58:41 +00:00
}
2024-05-19 16:00:03 +00:00
func (api *API2) GetRecentTariffs(ctx *fiber.Ctx) error {
2024-05-20 14:29:45 +00:00
userID, ok := api.extractUserID(ctx)
if !ok || userID == "" {
2024-05-19 16:00:03 +00:00
return api.noauth(ctx)
2024-02-01 13:48:29 +00:00
}
2024-05-19 16:00:03 +00:00
tariffs, err := api.history.GetRecentTariffs(ctx.Context(), userID)
2024-02-01 13:48:29 +00:00
if err != nil {
api.logger.Error("failed to get recent tariffs on <GetRecentTariffs> of <API2>",
zap.String("userId", userID),
zap.Error(err),
)
return api.errorOld(ctx, err)
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(tariffs)
2023-11-05 13:58:41 +00:00
}
2023-12-22 15:12:43 +00:00
2024-05-19 16:00:03 +00:00
func (api *API2) SendReport(ctx *fiber.Ctx) error {
var req struct {
Id string `json:"id"`
}
if err := ctx.BodyParser(&req); err != nil {
2024-02-02 09:56:33 +00:00
api.logger.Error("failed to bind request", zap.Error(err))
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusBadRequest, "failed to bind request")
2024-02-02 09:56:33 +00:00
}
if req.Id == "" {
2024-02-01 13:48:29 +00:00
api.logger.Error("history id is missing in <GetHistoryById> of <HistoryService>")
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusBadRequest, "history id is missing")
2024-02-01 13:48:29 +00:00
}
2024-05-19 16:00:03 +00:00
tariffs, err := api.history.GetHistoryByID(ctx.Context(), req.Id)
2024-02-01 13:48:29 +00:00
if err != nil {
api.logger.Error(
"failed to get history by id in <GetHistoryById> of <HistoryService>",
2024-02-02 09:56:33 +00:00
zap.String("historyID", req.Id),
2024-02-01 13:48:29 +00:00
zap.Error(err),
)
return api.errorOld(ctx, err)
}
if tariffs.Key != models.CustomerHistoryKeyPayCart {
api.logger.Error(
"invalid history record key",
2024-02-02 09:56:33 +00:00
zap.String("historyID", req.Id),
2024-02-01 13:48:29 +00:00
zap.Error(err),
)
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusBadRequest, "invalid history record key")
2024-02-01 13:48:29 +00:00
}
2024-05-19 16:00:03 +00:00
historyMap, err := api.history.GetDocNumber(ctx.Context(), tariffs.UserID)
2024-02-01 13:48:29 +00:00
if err != nil {
api.logger.Error(
"failed to get history of sorting by date created in <GetDocNumber> of <HistoryService>",
2024-02-02 09:56:33 +00:00
zap.String("historyID", req.Id),
2024-02-01 13:48:29 +00:00
zap.Error(err),
)
return api.errorOld(ctx, err)
}
2024-05-19 16:00:03 +00:00
token := ctx.Get("Authorization")
2024-03-11 17:21:32 +00:00
fmt.Println("HEADERS", ctx.Request().Header)
2024-02-01 13:48:29 +00:00
2024-05-19 16:00:03 +00:00
verifuser, err := api.clients.verify.GetVerification(ctx.Context(), token, tariffs.UserID)
2024-02-01 13:48:29 +00:00
if err != nil {
api.logger.Error("failed to get user verification on <GetHistoryById> of <HistoryService>",
zap.Error(err),
zap.String("userID", tariffs.UserID),
)
return api.errorOld(ctx, err)
}
if !verifuser.Accepted {
api.logger.Error(
"verification not accepted",
zap.String("userID", tariffs.UserID),
zap.Error(err),
)
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusBadRequest, "verification not accepted")
2024-02-01 13:48:29 +00:00
}
2024-05-19 16:00:03 +00:00
account, err := api.account.FindByUserID(ctx.Context(), tariffs.UserID)
2024-05-16 17:40:57 +00:00
if err != nil {
return api.errorOld(ctx, err)
}
2024-05-19 16:00:03 +00:00
authuser, err := api.clients.auth.GetUser(ctx.Context(), tariffs.UserID)
2024-02-01 13:48:29 +00:00
if err != nil {
api.logger.Error("failed to get user on <GetHistoryById> of <HistoryService>",
zap.Error(err),
zap.String("userID", tariffs.UserID),
)
return api.errorOld(ctx, err)
}
fileContents, readerr := os.ReadFile("./report.docx")
if readerr != nil {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusInternalServerError, "failed to read file")
2024-02-01 13:48:29 +00:00
}
2024-05-16 19:53:21 +00:00
if account.Name.Orgname == "" {
account.Name.Orgname = "Безымянное предприятие"
}
2024-02-01 13:48:29 +00:00
for _, tariff := range tariffs.RawDetails.Tariffs {
totalAmount := uint64(0)
2024-05-17 21:15:11 +00:00
privilegeMeasurement := ""
piecePrice := ""
privilegeName := ""
2024-02-01 13:48:29 +00:00
for _, privilege := range tariff.Privileges {
totalAmount += privilege.Amount
2024-05-17 21:15:11 +00:00
privilegeMeasurement = string(privilege.Type)
2024-05-19 16:00:03 +00:00
piecePrice = fmt.Sprintf("%.2f", float64(privilege.Price)/100)
2024-05-17 21:15:11 +00:00
privilegeName = privilege.Name
2024-02-01 13:48:29 +00:00
}
data := models.RespGeneratorService{
2024-05-16 17:32:15 +00:00
DocNumber: fmt.Sprint(historyMap[req.Id] + 1),
2024-02-01 13:48:29 +00:00
Date: time.Now().Format("2006-01-02"),
OrgTaxNum: verifuser.TaxNumber,
2024-05-16 17:40:57 +00:00
OrgName: account.Name.Orgname,
2024-05-17 21:15:11 +00:00
Name: tariff.Name + " " + privilegeName,
2024-05-16 19:40:48 +00:00
Amount: fmt.Sprint(totalAmount),
2024-05-19 16:00:03 +00:00
Unit: piecePrice,
Price: fmt.Sprintf("%.2f", float64(tariffs.RawDetails.Price)/100),
2024-05-17 21:15:11 +00:00
Sum: privilegeMeasurement,
2024-02-01 13:48:29 +00:00
}
2024-05-19 16:00:03 +00:00
err = api.clients.template.SendData(ctx.Context(), data, fileContents, authuser.Login)
2024-02-01 13:48:29 +00:00
if err != nil {
api.logger.Error("failed to send report to user on <GetHistoryById> of <HistoryService>",
zap.Error(err),
zap.String("userID", tariffs.UserID),
)
return api.errorOld(ctx, err)
}
}
2024-05-19 16:00:03 +00:00
return ctx.SendStatus(fiber.StatusOK)
2023-12-22 15:12:43 +00:00
}
2024-02-04 19:30:57 +00:00
2024-05-19 16:00:03 +00:00
func (api *API2) PostWalletRspay(ctx *fiber.Ctx) error {
2024-05-20 14:29:45 +00:00
userID, ok := api.extractUserID(ctx)
if !ok || userID == "" {
2024-02-05 12:24:56 +00:00
return api.noauth(ctx)
}
2024-05-19 16:00:03 +00:00
var req struct {
Money *float32 `json:"money,omitempty"`
}
if err := ctx.BodyParser(&req); err != nil {
api.logger.Error("failed to bind request", zap.Error(err))
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusBadRequest, "failed to bind request")
}
2024-05-19 16:00:03 +00:00
user, err := api.account.FindByUserID(ctx.Context(), userID)
2024-02-05 12:24:56 +00:00
if err != nil {
return api.errorOld(ctx, err)
}
if user.Status != models.AccountStatusNko && user.Status != models.AccountStatusOrg {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusForbidden, "not allowed for non organizations")
2024-02-05 12:24:56 +00:00
}
2024-05-19 16:00:03 +00:00
token := ctx.Get("Authorization")
2024-03-11 17:21:32 +00:00
fmt.Println("HEADERS", ctx.Request().Header)
2024-02-05 12:24:56 +00:00
2024-05-19 16:00:03 +00:00
verification, err := api.clients.verify.GetVerification(ctx.Context(), token, userID)
2024-02-05 12:24:56 +00:00
if err == errors.ErrNotFound {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusForbidden, "no verification data found")
2024-02-05 12:24:56 +00:00
}
if (user.Status == models.AccountStatusOrg && len(verification.Files) != 3) ||
(user.Status == models.AccountStatusNko && len(verification.Files) != 4) {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusForbidden, "not enough verification files")
2024-02-05 12:24:56 +00:00
}
2024-05-19 16:00:03 +00:00
authData, err := api.clients.auth.GetUser(ctx.Context(), userID)
2024-02-05 12:24:56 +00:00
if err != nil {
return api.errorOld(ctx, err)
}
err = api.clients.mail.SendMessage(authData.Login, verification, *req.Money)
2024-02-05 12:24:56 +00:00
if err != nil {
return api.errorOld(ctx, err)
}
2024-05-19 16:00:03 +00:00
return ctx.SendStatus(fiber.StatusOK)
2024-02-04 19:30:57 +00:00
}
2024-04-15 09:27:00 +00:00
type QuizLogoStat2 struct {
Count int64 `json:"count,omitempty"`
Items map[string]Item `json:"items,omitempty"`
}
type Item struct {
Money int64 `json:"money,omitempty"`
Quizes map[string][2]int `json:"quizes,omitempty"`
Regs int `json:"regs,omitempty"`
}
2024-05-19 16:00:03 +00:00
func (api *API2) QuizLogoStat(ctx *fiber.Ctx) error {
var req struct {
From *int `json:"from,omitempty"`
Limit *int `json:"limit,omitempty"`
Page *int `json:"page,omitempty"`
To *int `json:"to,omitempty"`
}
if err := ctx.BodyParser(&req); err != nil {
2024-04-15 09:27:00 +00:00
api.logger.Error("failed to bind request", zap.Error(err))
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusBadRequest, "failed to bind request")
2024-04-15 09:27:00 +00:00
}
2024-05-19 16:00:03 +00:00
result, err := api.account.QuizLogoStat(ctx.Context(), repository.QuizLogoStatDeps{
2024-04-15 09:27:00 +00:00
Page: req.Page,
Limit: req.Limit,
From: req.From,
To: req.To,
})
if err != nil {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting quiz logo stat", err.Error()))
2024-04-15 09:27:00 +00:00
}
2024-04-16 17:02:44 +00:00
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(result)
2024-04-15 09:27:00 +00:00
}
2024-04-25 17:25:19 +00:00
2024-05-19 16:00:03 +00:00
func (api *API2) PromocodeLTV(ctx *fiber.Ctx) error {
var req struct {
From int `json:"from"`
To int `json:"to"`
}
if err := ctx.BodyParser(&req); err != nil {
2024-04-25 17:25:19 +00:00
api.logger.Error("failed to bind request", zap.Error(err))
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusBadRequest, "failed to bind request")
2024-04-25 17:25:19 +00:00
}
2024-04-26 15:49:40 +00:00
// получаем мапу вида [promoID] = []{userid,timeActivate}
// отдаются только первые использованые на аккаунте промокоды, соответсвенно подсчет идет сугубо по ним
// если в запросе время различается с временем активации - если меньше, то учитывается только после применения
// если больше, то учитывается только с начала переданного from
2024-05-19 16:00:03 +00:00
codewordData, err := api.clients.codeword.GetAllPromoActivations(ctx.Context(), &codeword_rpc.Time{
2024-04-26 16:00:22 +00:00
To: int64(req.To),
From: int64(req.From),
2024-04-26 15:49:40 +00:00
})
2024-04-25 17:25:19 +00:00
if err != nil {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting codeword data", err.Error()))
2024-04-25 17:25:19 +00:00
}
2024-05-19 16:00:03 +00:00
userSumMap, er := api.history.GetPayUsersPromoHistory(ctx.Context(), codewordData, int64(req.From), int64(req.To))
2024-04-26 15:49:40 +00:00
if er != nil {
2024-05-19 16:00:03 +00:00
return api.error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed calculate promo users paid sum", er.Error()))
2024-04-26 15:49:40 +00:00
}
resp := make(map[string]struct {
Regs int
Money int64
})
for promoID, data := range codewordData {
2024-05-19 16:00:03 +00:00
fmt.Println("PROTOMOTO", promoID, data)
for _, value := range data {
2024-04-26 15:49:40 +00:00
paids, ok := userSumMap[value.UserID]
if !ok {
paids = 0
}
2024-05-19 16:00:03 +00:00
fmt.Println("PROTOMOTO1", paids, value)
2024-04-26 15:49:40 +00:00
2024-04-26 16:00:22 +00:00
if value.Time >= int64(req.From) && value.Time <= int64(req.To) {
2024-04-26 15:49:40 +00:00
if _, ok := resp[promoID]; !ok {
resp[promoID] = struct {
Regs int
Money int64
}{Regs: 1, Money: paids}
continue
}
2024-05-03 22:04:32 +00:00
current := resp[promoID]
current.Regs += 1
current.Money += paids
resp[promoID] = current
2024-04-26 15:49:40 +00:00
}
}
}
2024-05-19 16:00:03 +00:00
return ctx.Status(fiber.StatusOK).JSON(resp)
2024-04-25 17:25:19 +00:00
}