2023-11-05 13:58:41 +00:00
|
|
|
package swagger
|
|
|
|
|
|
|
|
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"
|
2023-11-06 08:30:41 +00:00
|
|
|
"net/http"
|
2024-02-01 13:48:29 +00:00
|
|
|
"os"
|
2023-11-07 05:14:04 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
2024-04-13 10:26:32 +00:00
|
|
|
"net/url"
|
|
|
|
|
2023-11-06 08:30:41 +00:00
|
|
|
|
2023-11-05 13:58:41 +00:00
|
|
|
"github.com/labstack/echo/v4"
|
|
|
|
"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"
|
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"
|
2023-11-06 08:30:41 +00:00
|
|
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/echotools"
|
2023-11-07 05:14:04 +00:00
|
|
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate"
|
2024-04-13 10:26:32 +00:00
|
|
|
qutils "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/utils"
|
|
|
|
|
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-13 10:26:32 +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
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ ServerInterface = (*API2)(nil)
|
|
|
|
|
2024-04-13 10:26:32 +00:00
|
|
|
func NewAPI2(logger *zap.Logger, db *mongo.Database, config *models.Config, consumer *tariff.Consumer, producer *tariff.Producer, encrypt *qutils.Encrypt) API2 {
|
2023-11-05 13:58:41 +00:00
|
|
|
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,
|
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,
|
|
|
|
}),
|
2023-11-07 05:14:04 +00:00
|
|
|
},
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-08 04:40:38 +00:00
|
|
|
func (api *API2) error(ctx echo.Context, status int, message string, rest ...any) error {
|
|
|
|
if len(rest) > 0 {
|
|
|
|
message = fmt.Sprintf(message, rest...)
|
|
|
|
}
|
|
|
|
api.logger.Error(message)
|
|
|
|
return ctx.JSON(status, models.ResponseErrorHTTP{
|
|
|
|
StatusCode: status,
|
|
|
|
Message: message,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-11-08 07:04:18 +00:00
|
|
|
func (api *API2) errorOld(ctx echo.Context, err errors.Error) error {
|
|
|
|
api.logger.Error("error:", zap.Error(err))
|
|
|
|
return errors.HTTP(ctx, err)
|
|
|
|
}
|
|
|
|
|
2023-11-08 06:06:19 +00:00
|
|
|
func (api *API2) noauth(ctx echo.Context) error {
|
|
|
|
return api.error(ctx, http.StatusUnauthorized, "failed to get jwt payload")
|
|
|
|
}
|
|
|
|
|
2023-11-06 08:30:41 +00:00
|
|
|
// Health
|
|
|
|
|
|
|
|
func (api *API2) GetHealth(ctx echo.Context) error {
|
|
|
|
return ctx.String(http.StatusOK, "OK")
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 08:30:41 +00:00
|
|
|
// Account
|
|
|
|
|
|
|
|
func (api *API2) DeleteAccount(ctx echo.Context) error {
|
2023-11-06 09:31:39 +00:00
|
|
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
if !ok {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.noauth(ctx)
|
2023-11-06 09:31:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
account, err := api.account.Remove(ctx.Request().Context(), userID)
|
|
|
|
if err != nil {
|
2023-11-08 07:04:18 +00:00
|
|
|
return api.errorOld(ctx, err)
|
2023-11-06 09:31:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, account)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (api *API2) ChangeAccount(ctx echo.Context) error {
|
2023-11-06 08:30:41 +00:00
|
|
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
if !ok {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.noauth(ctx)
|
2023-11-06 08:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
request, bindErr := echotools.Bind[models.Name](ctx)
|
|
|
|
if bindErr != nil {
|
2023-11-08 05:14:13 +00:00
|
|
|
return api.error(ctx, http.StatusBadRequest, "failed to bind json: %w", bindErr)
|
2023-11-06 08:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
account, err := api.account.UpdateName(ctx.Request().Context(), userID, request)
|
|
|
|
if err != nil {
|
2023-11-08 07:04:18 +00:00
|
|
|
return api.errorOld(ctx, err)
|
2023-11-06 08:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, account)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 08:30:41 +00:00
|
|
|
func (api *API2) SetAccountVerificationStatus(ctx echo.Context, userID string) error {
|
|
|
|
request, bindErr := echotools.Bind[models.SetAccountStatus](ctx)
|
|
|
|
if bindErr != nil {
|
2023-11-08 05:14:13 +00:00
|
|
|
return api.error(ctx, http.StatusBadRequest, "failed to bind json: %w", bindErr)
|
2023-11-06 08:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
account, err := api.account.SetStatus(ctx.Request().Context(), userID, request.Status)
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, account)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 08:30:41 +00:00
|
|
|
func (api *API2) GetAccount(ctx echo.Context) error {
|
2023-11-06 10:30:07 +00:00
|
|
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
if !ok {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.noauth(ctx)
|
2023-11-06 10:30:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
account, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
|
|
|
if err != nil {
|
2023-11-08 07:04:18 +00:00
|
|
|
return api.errorOld(ctx, err)
|
2023-11-06 10:30:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, account)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 08:30:41 +00:00
|
|
|
func (api *API2) AddAccount(ctx echo.Context) error {
|
2023-11-06 10:30:07 +00:00
|
|
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
if !ok {
|
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-04-12 23:31:56 +00:00
|
|
|
var quizFrom, quizUser string
|
2024-03-22 18:51:36 +00:00
|
|
|
cookie, er := ctx.Request().Cookie("quizFrom")
|
|
|
|
if er == nil {
|
|
|
|
quizFrom = cookie.Value
|
|
|
|
}
|
2024-04-12 23:31:56 +00:00
|
|
|
cookie, er = ctx.Request().Cookie("quizUser")
|
|
|
|
if er == nil {
|
2024-04-13 10:26:32 +00:00
|
|
|
quizUser, er = url.QueryUnescape(cookie.Value)
|
|
|
|
if er == nil {
|
|
|
|
quizUser, er = api.encrypt.DecryptStr([]byte(quizUser))
|
|
|
|
fmt.Println("DECERR", er)
|
|
|
|
}
|
2024-04-12 23:31:56 +00:00
|
|
|
}
|
2023-11-06 10:30:07 +00:00
|
|
|
|
|
|
|
account, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
|
|
|
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 {
|
2023-11-08 05:14:13 +00:00
|
|
|
return api.error(ctx, http.StatusBadRequest, "account exists")
|
2023-11-06 10:30:07 +00:00
|
|
|
}
|
|
|
|
|
2023-11-07 05:14:04 +00:00
|
|
|
user, err := api.clients.auth.GetUser(ctx.Request().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-04-12 23:31:56 +00:00
|
|
|
account, err = api.account.Insert(ctx.Request().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
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, account)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 08:30:41 +00:00
|
|
|
func (api *API2) DeleteDirectAccount(ctx echo.Context, userID string) error {
|
2023-11-06 11:51:55 +00:00
|
|
|
account, err := api.account.Remove(ctx.Request().Context(), userID)
|
|
|
|
if err != nil {
|
2023-11-08 07:04:18 +00:00
|
|
|
return api.errorOld(ctx, err)
|
2023-11-06 11:51:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, account)
|
2023-11-06 08:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (api *API2) GetDirectAccount(ctx echo.Context, userID string) error {
|
2023-11-06 11:54:15 +00:00
|
|
|
account, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
|
|
|
if err != nil {
|
2023-11-08 07:04:18 +00:00
|
|
|
return api.errorOld(ctx, err)
|
2023-11-06 11:54:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, account)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (api *API2) PaginationAccounts(ctx echo.Context, params PaginationAccountsParams) error {
|
2023-11-08 05:52:47 +00:00
|
|
|
if params.Page == nil || params.Limit == nil {
|
|
|
|
return api.error(ctx, http.StatusInternalServerError, "default values missing for PaginationAccounts")
|
2023-11-06 12:02:13 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 20:25:30 +00:00
|
|
|
page := int64(math.Max(float64(*params.Page), 1))
|
|
|
|
limit := int64(math.Max(float64(*params.Limit), 1))
|
|
|
|
limit = int64(math.Min(float64(limit), float64(models.DefaultLimit)))
|
2023-11-08 05:52:47 +00:00
|
|
|
|
2023-11-06 12:02:13 +00:00
|
|
|
count, err := api.account.CountAll(ctx.Request().Context())
|
|
|
|
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{}}
|
|
|
|
return ctx.JSON(http.StatusOK, response)
|
|
|
|
}
|
|
|
|
|
2023-11-08 05:52:47 +00:00
|
|
|
totalPages := int64(math.Ceil(float64(count) / float64(limit)))
|
2023-11-06 12:02:13 +00:00
|
|
|
|
2023-11-08 05:52:47 +00:00
|
|
|
accounts, err := api.account.FindMany(ctx.Request().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,
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, response)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 08:30:41 +00:00
|
|
|
// Cart
|
|
|
|
|
2023-11-05 13:58:41 +00:00
|
|
|
func (api *API2) RemoveFromCart(ctx echo.Context, params RemoveFromCartParams) error {
|
2023-11-07 05:14:04 +00:00
|
|
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
if !ok {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.noauth(ctx)
|
2023-11-07 05:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if validate.IsStringEmpty(params.Id) {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.error(ctx, http.StatusBadRequest, "empty item id")
|
2023-11-07 05:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cartItems, err := api.account.RemoveItemFromCart(ctx.Request().Context(), userID, params.Id)
|
|
|
|
if err != nil {
|
2023-11-08 07:04:18 +00:00
|
|
|
return api.errorOld(ctx, err)
|
2023-11-07 05:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, cartItems)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (api *API2) Add2cart(ctx echo.Context, params Add2cartParams) error {
|
2023-11-07 05:14:04 +00:00
|
|
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
if !ok {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.noauth(ctx)
|
2023-11-07 05:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
token, ok := ctx.Get(models.AuthJWTDecodedAccessTokenKey).(string)
|
|
|
|
if !ok {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.noauth(ctx)
|
2023-11-07 05:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if validate.IsStringEmpty(params.Id) {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.error(ctx, http.StatusBadRequest, "empty item id")
|
2023-11-07 05:14:04 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 06:06:19 +00:00
|
|
|
tariffID := params.Id
|
2023-11-07 05:14:04 +00:00
|
|
|
|
2023-11-08 06:06:19 +00:00
|
|
|
tariff, err := api.clients.hubadmin.GetTariff(ctx.Request().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 {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.error(ctx, http.StatusNotFound, "tariff not found")
|
2023-11-07 05:14:04 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 06:06:19 +00:00
|
|
|
cartItems, err := api.account.AddItemToCart(ctx.Request().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
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, cartItems)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (api *API2) PayCart(ctx echo.Context) error {
|
2023-11-07 05:14:04 +00:00
|
|
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
if !ok {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.noauth(ctx)
|
2023-11-07 05:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
accessToken, ok := ctx.Get(models.AuthJWTDecodedAccessTokenKey).(string)
|
|
|
|
if !ok {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.noauth(ctx)
|
2023-11-07 05:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
account, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
|
|
|
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))
|
|
|
|
|
|
|
|
tariffs, err := api.clients.hubadmin.GetTariffs(ctx.Request().Context(), accessToken, account.Cart)
|
|
|
|
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)
|
|
|
|
|
|
|
|
discountResponse, err := api.clients.discount.Apply(ctx.Request().Context(), &discount.ApplyDiscountRequest{
|
|
|
|
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) {
|
2023-11-08 06:06:19 +00:00
|
|
|
return api.error(ctx, http.StatusPaymentRequired, "insufficient funds: %d", int64(discountResponse.Price)-account.Wallet.Money)
|
2023-11-07 05:14:04 +00:00
|
|
|
}
|
|
|
|
|
2024-03-11 18:44:01 +00:00
|
|
|
for _, applied := range discountResponse.AppliedDiscounts {
|
|
|
|
if applied.Condition.User != nil && *applied.Condition.User != "" {
|
|
|
|
_, err := api.clients.discount.DeleteDiscount(ctx.Request().Context(), &discount.GetDiscountByIDRequest{
|
|
|
|
ID: applied.ID,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return api.error(ctx, http.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 {
|
2023-11-07 08:13:22 +00:00
|
|
|
accountx, err := api.account.ChangeWallet(ctx.Request().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 {
|
|
|
|
cash, err := api.clients.currency.Translate(ctx.Request().Context(), &models.TranslateCurrency{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2023-11-07 08:13:22 +00:00
|
|
|
accountx, err := api.account.ChangeWallet(ctx.Request().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
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := api.history.Insert(ctx.Request().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()
|
|
|
|
|
|
|
|
if err := api.producer.Send(ctx.Request().Context(), userID, ¤tTariff); 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))
|
|
|
|
}
|
2023-11-08 06:41:25 +00:00
|
|
|
return api.error(ctx, http.StatusInternalServerError, "failed to send tariffs to broker")
|
2023-11-07 05:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := api.account.ClearCart(ctx.Request().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{}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, updatedAccount)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 08:30:41 +00:00
|
|
|
// Currency
|
|
|
|
|
2023-11-05 13:58:41 +00:00
|
|
|
func (api *API2) GetCurrencies(ctx echo.Context) error {
|
2023-11-07 08:13:22 +00:00
|
|
|
currencyList, err := api.currency.FindCurrenciesList(ctx.Request().Context(), models.DefaultCurrencyListName)
|
|
|
|
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 {
|
|
|
|
return ctx.JSON(http.StatusOK, []string{})
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, currencyList)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (api *API2) UpdateCurrencies(ctx echo.Context) error {
|
2023-11-07 08:13:22 +00:00
|
|
|
currenciesPtr, bindErr := echotools.Bind[[]string](ctx)
|
|
|
|
if bindErr != nil {
|
2023-11-08 06:41:25 +00:00
|
|
|
return api.error(ctx, http.StatusBadRequest, "faild to bind currencies")
|
2023-11-07 08:13:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
currencies := *currenciesPtr
|
|
|
|
|
|
|
|
currencyList, err := api.currency.ReplaceCurrencies(ctx.Request().Context(), &models.CurrencyList{
|
|
|
|
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 {
|
|
|
|
newCurrencyList, err := api.currency.Insert(ctx.Request().Context(), &models.CurrencyList{
|
|
|
|
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
|
|
|
}
|
|
|
|
return ctx.JSON(http.StatusOK, newCurrencyList.Currencies)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, currencyList.Currencies)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 08:30:41 +00:00
|
|
|
// History
|
|
|
|
|
2023-11-05 13:58:41 +00:00
|
|
|
func (api *API2) GetHistory(ctx echo.Context, params GetHistoryParams) error {
|
2024-03-07 16:43:00 +00:00
|
|
|
var userID string
|
|
|
|
|
|
|
|
if params.AccountID != nil && *params.AccountID != "" {
|
|
|
|
userID = *params.AccountID
|
|
|
|
} else {
|
|
|
|
userID, _ = ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
}
|
|
|
|
|
2023-11-07 05:14:04 +00:00
|
|
|
dto := &history.GetHistories{
|
2024-03-07 16:43:00 +00:00
|
|
|
UserID: userID,
|
2024-03-11 17:21:32 +00:00
|
|
|
Type: params.Type,
|
2023-11-07 05:14:04 +00:00
|
|
|
Pagination: &models.Pagination{
|
|
|
|
Page: int64(*params.Page),
|
|
|
|
Limit: int64(*params.Limit),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
count, err := api.history.CountAll(ctx.Request().Context(), dto)
|
|
|
|
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{}}
|
|
|
|
return ctx.JSON(http.StatusOK, returnHistories)
|
|
|
|
}
|
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
|
|
|
|
2023-11-08 06:41:25 +00:00
|
|
|
histories, err := api.history.FindMany(ctx.Request().Context(), dto)
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, 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
|
|
|
|
|
|
|
func (api *API2) RequestMoney(ctx echo.Context) error {
|
2023-11-07 08:13:22 +00:00
|
|
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
if !ok {
|
2023-11-08 06:41:25 +00:00
|
|
|
return api.noauth(ctx)
|
2023-11-07 08:13:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
request, bindErr := echotools.Bind[models.GetPaymentLinkBody](ctx)
|
|
|
|
if bindErr != nil {
|
2023-11-08 06:41:25 +00:00
|
|
|
return api.error(ctx, http.StatusBadRequest, "faild to bind payment link")
|
2023-11-07 08:13:22 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 06:41:25 +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
|
|
|
}
|
|
|
|
|
|
|
|
link, err := api.GetPaymentLink(ctx.Request().Context(), &models.GetPaymentLinkRequest{
|
|
|
|
Body: request,
|
|
|
|
UserID: userID,
|
|
|
|
ClientIP: ctx.RealIP(),
|
|
|
|
})
|
|
|
|
if err != nil {
|
2023-11-08 07:04:18 +00:00
|
|
|
return api.errorOld(ctx, err)
|
2023-11-07 08:13:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, &models.GetPaymentLinkResponse{Link: link})
|
2023-11-06 08:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (api *API2) ChangeCurrency(ctx echo.Context) error {
|
2023-11-07 08:13:22 +00:00
|
|
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
if !ok {
|
2023-11-08 06:41:25 +00:00
|
|
|
return api.noauth(ctx)
|
2023-11-07 08:13:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
request, bindErr := echotools.Bind[models.ChangeCurrency](ctx)
|
|
|
|
if bindErr != nil {
|
2023-11-08 06:41:25 +00:00
|
|
|
return api.error(ctx, http.StatusBadRequest, "faild to bind currency")
|
2023-11-07 08:13:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if validate.IsStringEmpty(request.Currency) {
|
2023-11-08 06:41:25 +00:00
|
|
|
return api.error(ctx, http.StatusBadRequest, "empty currency")
|
2023-11-07 08:13:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
currency := request.Currency
|
|
|
|
account, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
|
|
|
if err != nil {
|
2023-11-08 07:04:18 +00:00
|
|
|
return api.errorOld(ctx, err)
|
2023-11-07 08:13:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cash, err := api.clients.currency.Translate(ctx.Request().Context(), &models.TranslateCurrency{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
updatedAccount, err := api.account.ChangeWallet(ctx.Request().Context(), account.UserID, &models.Wallet{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, updatedAccount)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
2023-11-05 13:58:41 +00:00
|
|
|
|
2024-01-31 20:25:30 +00:00
|
|
|
func (api *API2) CalculateLTV(ctx echo.Context) error {
|
2024-02-01 13:48:29 +00:00
|
|
|
var req CalculateLTVJSONBody
|
|
|
|
|
|
|
|
if err := ctx.Bind(&req); err != nil {
|
|
|
|
api.logger.Error("failed to bind request", zap.Error(err))
|
|
|
|
return api.error(ctx, http.StatusBadRequest, "failed to bind request")
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.From > req.To && req.To != 0 {
|
|
|
|
api.logger.Error("From timestamp must be less than To timestamp unless To is 0")
|
|
|
|
return api.error(ctx, http.StatusBadRequest, "From timestamp must be less than To timestamp unless To is 0")
|
|
|
|
}
|
|
|
|
|
|
|
|
ltv, err := api.history.CalculateCustomerLTV(ctx.Request().Context(), req.From, req.To)
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, response)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 20:25:30 +00:00
|
|
|
func (api *API2) GetRecentTariffs(ctx echo.Context) error {
|
2024-02-01 13:48:29 +00:00
|
|
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
if !ok {
|
|
|
|
api.logger.Error("failed to convert jwt payload to string on <GetRecentTariffs> of <API2>")
|
|
|
|
return api.error(ctx, http.StatusBadRequest, "failed to convert jwt payload to string")
|
|
|
|
}
|
|
|
|
|
|
|
|
if userID == "" {
|
|
|
|
api.logger.Error("user id is missing in <GetRecentTariffs> of <API2>")
|
|
|
|
return api.error(ctx, http.StatusBadRequest, "user id is missing")
|
|
|
|
}
|
|
|
|
|
|
|
|
tariffs, err := api.history.GetRecentTariffs(ctx.Request().Context(), userID)
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.JSON(http.StatusOK, tariffs)
|
2023-11-05 13:58:41 +00:00
|
|
|
}
|
2023-12-22 15:12:43 +00:00
|
|
|
|
2024-01-31 20:25:30 +00:00
|
|
|
func (api *API2) SendReport(ctx echo.Context) error {
|
2024-02-02 09:56:33 +00:00
|
|
|
var req SendReportJSONBody
|
|
|
|
if err := ctx.Bind(&req); err != nil {
|
|
|
|
api.logger.Error("failed to bind request", zap.Error(err))
|
|
|
|
return api.error(ctx, http.StatusBadRequest, "failed to bind request")
|
|
|
|
}
|
|
|
|
|
|
|
|
if req.Id == "" {
|
2024-02-01 13:48:29 +00:00
|
|
|
api.logger.Error("history id is missing in <GetHistoryById> of <HistoryService>")
|
|
|
|
return api.error(ctx, http.StatusBadRequest, "history id is missing")
|
|
|
|
}
|
|
|
|
|
2024-02-02 09:56:33 +00:00
|
|
|
tariffs, err := api.history.GetHistoryByID(ctx.Request().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),
|
|
|
|
)
|
|
|
|
return api.error(ctx, http.StatusBadRequest, "invalid history record key")
|
|
|
|
}
|
|
|
|
|
|
|
|
historyMap, err := api.history.GetDocNumber(ctx.Request().Context(), tariffs.UserID)
|
|
|
|
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-03-11 17:21:32 +00:00
|
|
|
token := ctx.Request().Header.Get("Authorization")
|
|
|
|
fmt.Println("HEADERS", ctx.Request().Header)
|
2024-02-01 13:48:29 +00:00
|
|
|
|
2024-03-11 17:21:32 +00:00
|
|
|
verifuser, err := api.clients.verify.GetVerification(ctx.Request().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),
|
|
|
|
)
|
|
|
|
return api.error(ctx, http.StatusBadRequest, "verification not accepted")
|
|
|
|
}
|
|
|
|
|
|
|
|
authuser, err := api.clients.auth.GetUser(ctx.Request().Context(), tariffs.UserID)
|
|
|
|
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 {
|
|
|
|
return api.error(ctx, http.StatusInternalServerError, "failed to read file")
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tariff := range tariffs.RawDetails.Tariffs {
|
|
|
|
totalAmount := uint64(0)
|
|
|
|
for _, privilege := range tariff.Privileges {
|
|
|
|
totalAmount += privilege.Amount
|
|
|
|
}
|
|
|
|
data := models.RespGeneratorService{
|
2024-02-02 09:56:33 +00:00
|
|
|
DocNumber: historyMap[req.Id] + 1,
|
2024-02-01 13:48:29 +00:00
|
|
|
Date: time.Now().Format("2006-01-02"),
|
|
|
|
OrgTaxNum: verifuser.TaxNumber,
|
|
|
|
OrgName: models.Name{Orgname: "Orgname"},
|
|
|
|
Name: tariff.Name,
|
|
|
|
Amount: totalAmount,
|
|
|
|
Price: tariffs.RawDetails.Price,
|
|
|
|
Sum: tariffs.RawDetails.Price,
|
|
|
|
}
|
|
|
|
err = api.clients.template.SendData(ctx.Request().Context(), data, fileContents, authuser.Email)
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.NoContent(http.StatusOK)
|
2023-12-22 15:12:43 +00:00
|
|
|
}
|
2024-02-04 19:30:57 +00:00
|
|
|
|
2024-02-05 12:24:56 +00:00
|
|
|
func (api *API2) PostWalletRspay(ctx echo.Context) error {
|
|
|
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
|
|
|
if !ok {
|
|
|
|
return api.noauth(ctx)
|
|
|
|
}
|
|
|
|
|
2024-02-15 09:03:24 +00:00
|
|
|
var req PostWalletRspayJSONBody
|
|
|
|
if err := ctx.Bind(&req); err != nil {
|
|
|
|
api.logger.Error("failed to bind request", zap.Error(err))
|
|
|
|
return api.error(ctx, http.StatusBadRequest, "failed to bind request")
|
|
|
|
}
|
|
|
|
|
2024-02-05 12:24:56 +00:00
|
|
|
user, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
|
|
|
if err != nil {
|
|
|
|
return api.errorOld(ctx, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if user.Status != models.AccountStatusNko && user.Status != models.AccountStatusOrg {
|
|
|
|
return api.error(ctx, http.StatusForbidden, "not allowed for non organizations")
|
|
|
|
}
|
2024-03-11 17:21:32 +00:00
|
|
|
token := ctx.Request().Header.Get("Authorization")
|
|
|
|
fmt.Println("HEADERS", ctx.Request().Header)
|
2024-02-05 12:24:56 +00:00
|
|
|
|
2024-03-11 17:21:32 +00:00
|
|
|
verification, err := api.clients.verify.GetVerification(ctx.Request().Context(), token, userID)
|
2024-02-05 12:24:56 +00:00
|
|
|
if err == errors.ErrNotFound {
|
|
|
|
return api.error(ctx, http.StatusForbidden, "no verification data found")
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user.Status == models.AccountStatusOrg && len(verification.Files) != 3) ||
|
|
|
|
(user.Status == models.AccountStatusNko && len(verification.Files) != 4) {
|
|
|
|
return api.error(ctx, http.StatusForbidden, "not enough verification files")
|
|
|
|
}
|
|
|
|
|
|
|
|
authData, err := api.clients.auth.GetUser(ctx.Request().Context(), userID)
|
|
|
|
if err != nil {
|
|
|
|
return api.errorOld(ctx, err)
|
|
|
|
}
|
|
|
|
|
2024-02-15 09:03:24 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.NoContent(http.StatusOK)
|
2024-02-04 19:30:57 +00:00
|
|
|
}
|