2024-05-21 13:50:26 +00:00
|
|
|
|
package history
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
"math"
|
|
|
|
|
"os"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
|
|
|
|
codeword_rpc "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/codeword"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/history"
|
2024-05-23 14:34:45 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils"
|
2024-05-21 13:50:26 +00:00
|
|
|
|
"strconv"
|
2024-05-23 14:34:45 +00:00
|
|
|
|
"strings"
|
2024-05-21 13:50:26 +00:00
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Deps struct {
|
|
|
|
|
MiddleWare *http.MiddleWare
|
|
|
|
|
HistoryRepo *repository.HistoryRepository
|
|
|
|
|
AccountRepo *repository.AccountRepository
|
|
|
|
|
VerifyClient *client.VerificationClient
|
|
|
|
|
AuthClient *client.AuthClient
|
|
|
|
|
TemplateClient *client.TemplateClient
|
|
|
|
|
CodewordClient *client.CodewordClient
|
|
|
|
|
Logger *zap.Logger
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type HistoryController struct {
|
|
|
|
|
middleWare *http.MiddleWare
|
|
|
|
|
historyRepo *repository.HistoryRepository
|
|
|
|
|
accountRepo *repository.AccountRepository
|
|
|
|
|
verifyClient *client.VerificationClient
|
|
|
|
|
authClient *client.AuthClient
|
|
|
|
|
templateClient *client.TemplateClient
|
|
|
|
|
codewordClient *client.CodewordClient
|
|
|
|
|
logger *zap.Logger
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewHistoryController(deps Deps) *HistoryController {
|
|
|
|
|
return &HistoryController{
|
|
|
|
|
middleWare: deps.MiddleWare,
|
|
|
|
|
historyRepo: deps.HistoryRepo,
|
|
|
|
|
authClient: deps.AuthClient,
|
|
|
|
|
accountRepo: deps.AccountRepo,
|
|
|
|
|
verifyClient: deps.VerifyClient,
|
|
|
|
|
templateClient: deps.TemplateClient,
|
|
|
|
|
codewordClient: deps.CodewordClient,
|
|
|
|
|
logger: deps.Logger,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-23 07:15:26 +00:00
|
|
|
|
func (receiver *HistoryController) Get(ctx *fiber.Ctx) error {
|
2024-05-21 13:50:26 +00:00
|
|
|
|
var userID string
|
|
|
|
|
|
|
|
|
|
pageStr := ctx.Query("page")
|
|
|
|
|
limitStr := ctx.Query("limit")
|
|
|
|
|
tipe := ctx.Query("type")
|
|
|
|
|
accountID := ctx.Query("accountID")
|
|
|
|
|
|
|
|
|
|
if accountID != "" {
|
|
|
|
|
userID = accountID
|
|
|
|
|
} else {
|
|
|
|
|
id, ok := receiver.middleWare.ExtractUserID(ctx)
|
|
|
|
|
if !ok || id == "" {
|
|
|
|
|
return receiver.middleWare.NoAuth(ctx)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
userID = id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
limit, err := strconv.ParseInt(limitStr, 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "invalid limit format")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
page, err := strconv.ParseInt(pageStr, 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "invalid page format")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dto := &history.GetHistories{
|
|
|
|
|
UserID: userID,
|
|
|
|
|
Type: &tipe,
|
|
|
|
|
Pagination: &models.Pagination{
|
|
|
|
|
Page: page,
|
|
|
|
|
Limit: limit,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count, err := receiver.historyRepo.CountAll(ctx.Context(), dto)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if count == 0 {
|
|
|
|
|
returnHistories := models.PaginationResponse[models.History]{TotalPages: 0, Records: []models.History{}}
|
|
|
|
|
return ctx.Status(fiber.StatusOK).JSON(returnHistories)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
totalPages := int64(math.Ceil(float64(count) / float64(dto.Pagination.Limit)))
|
|
|
|
|
|
|
|
|
|
histories, err := receiver.historyRepo.FindMany(ctx.Context(), dto)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
returnHistories := models.PaginationResponse[models.History]{
|
|
|
|
|
TotalPages: totalPages,
|
|
|
|
|
Records: histories,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ctx.Status(fiber.StatusOK).JSON(returnHistories)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (receiver *HistoryController) CalculateLTV(ctx *fiber.Ctx) error {
|
|
|
|
|
var req struct {
|
|
|
|
|
From int64 `json:"from"`
|
|
|
|
|
To int64 `json:"to"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := ctx.BodyParser(&req); err != nil {
|
|
|
|
|
receiver.logger.Error("failed to bind request", zap.Error(err))
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if req.From > req.To && req.To != 0 {
|
|
|
|
|
receiver.logger.Error("From timestamp must be less than To timestamp unless To is 0")
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "From timestamp must be less than To timestamp unless To is 0")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ltv, err := receiver.historyRepo.CalculateCustomerLTV(ctx.Context(), req.From, req.To)
|
|
|
|
|
if err != nil {
|
|
|
|
|
receiver.logger.Error("failed to calculate LTV", zap.Error(err))
|
|
|
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response := struct {
|
|
|
|
|
LTV int64 `json:"LTV"`
|
|
|
|
|
}{
|
|
|
|
|
LTV: ltv,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ctx.Status(fiber.StatusOK).JSON(response)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (receiver *HistoryController) GetRecentTariffs(ctx *fiber.Ctx) error {
|
|
|
|
|
userID, ok := receiver.middleWare.ExtractUserID(ctx)
|
|
|
|
|
if !ok || userID == "" {
|
|
|
|
|
return receiver.middleWare.NoAuth(ctx)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tariffs, err := receiver.historyRepo.GetRecentTariffs(ctx.Context(), userID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
receiver.logger.Error("failed to get recent tariffs on <GetRecentTariffs> of <API2>",
|
|
|
|
|
zap.String("userId", userID),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ctx.Status(fiber.StatusOK).JSON(tariffs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (receiver *HistoryController) SendReport(ctx *fiber.Ctx) error {
|
2024-05-23 14:34:45 +00:00
|
|
|
|
hlogger := receiver.middleWare.ExtractLogger(ctx)
|
|
|
|
|
|
2024-05-21 13:50:26 +00:00
|
|
|
|
var req struct {
|
|
|
|
|
Id string `json:"id"`
|
|
|
|
|
}
|
|
|
|
|
if err := ctx.BodyParser(&req); err != nil {
|
|
|
|
|
receiver.logger.Error("failed to bind request", zap.Error(err))
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if req.Id == "" {
|
|
|
|
|
receiver.logger.Error("history id is missing in <GetHistoryById> of <HistoryService>")
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "history id is missing")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tariffs, err := receiver.historyRepo.GetHistoryByID(ctx.Context(), req.Id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
receiver.logger.Error(
|
|
|
|
|
"failed to get history by id in <GetHistoryById> of <HistoryService>",
|
|
|
|
|
zap.String("historyID", req.Id),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if tariffs.Key != models.CustomerHistoryKeyPayCart {
|
|
|
|
|
receiver.logger.Error(
|
|
|
|
|
"invalid history record key",
|
|
|
|
|
zap.String("historyID", req.Id),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "invalid history record key")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
historyMap, err := receiver.historyRepo.GetDocNumber(ctx.Context(), tariffs.UserID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
receiver.logger.Error(
|
|
|
|
|
"failed to get history of sorting by date created in <GetDocNumber> of <HistoryService>",
|
|
|
|
|
zap.String("historyID", req.Id),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
token := ctx.Get("Authorization")
|
|
|
|
|
fmt.Println("HEADERS", ctx.Request().Header)
|
|
|
|
|
|
|
|
|
|
verifuser, err := receiver.verifyClient.GetVerification(ctx.Context(), token, tariffs.UserID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
receiver.logger.Error("failed to get user verification on <GetHistoryById> of <HistoryService>",
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
zap.String("userID", tariffs.UserID),
|
|
|
|
|
)
|
|
|
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
if !verifuser.Accepted {
|
|
|
|
|
receiver.logger.Error(
|
|
|
|
|
"verification not accepted",
|
|
|
|
|
zap.String("userID", tariffs.UserID),
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
)
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "verification not accepted")
|
|
|
|
|
}
|
|
|
|
|
account, err := receiver.accountRepo.FindByUserID(ctx.Context(), tariffs.UserID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
authuser, err := receiver.authClient.GetUser(ctx.Context(), tariffs.UserID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
receiver.logger.Error("failed to get user on <GetHistoryById> of <HistoryService>",
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
zap.String("userID", tariffs.UserID),
|
|
|
|
|
)
|
|
|
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fileContents, readerr := os.ReadFile("./report.docx")
|
|
|
|
|
if readerr != nil {
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, "failed to read file")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if account.Name.Orgname == "" {
|
|
|
|
|
account.Name.Orgname = "Безымянное предприятие"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tariff := range tariffs.RawDetails.Tariffs {
|
|
|
|
|
totalAmount := uint64(0)
|
|
|
|
|
privilegeMeasurement := ""
|
|
|
|
|
piecePrice := ""
|
|
|
|
|
privilegeName := ""
|
|
|
|
|
for _, privilege := range tariff.Privileges {
|
|
|
|
|
totalAmount += privilege.Amount
|
|
|
|
|
privilegeMeasurement = string(privilege.Type)
|
|
|
|
|
piecePrice = fmt.Sprintf("%.2f", float64(privilege.Price)/100)
|
|
|
|
|
privilegeName = privilege.Name
|
|
|
|
|
}
|
|
|
|
|
data := models.RespGeneratorService{
|
|
|
|
|
DocNumber: fmt.Sprint(historyMap[req.Id] + 1),
|
|
|
|
|
Date: time.Now().Format("2006-01-02"),
|
|
|
|
|
OrgTaxNum: verifuser.TaxNumber,
|
|
|
|
|
OrgName: account.Name.Orgname,
|
|
|
|
|
Name: tariff.Name + " " + privilegeName,
|
|
|
|
|
Amount: fmt.Sprint(totalAmount),
|
|
|
|
|
Unit: piecePrice,
|
|
|
|
|
Price: fmt.Sprintf("%.2f", float64(tariffs.RawDetails.Price)/100),
|
|
|
|
|
Sum: privilegeMeasurement,
|
|
|
|
|
}
|
|
|
|
|
err = receiver.templateClient.SendData(ctx.Context(), data, fileContents, authuser.Login)
|
|
|
|
|
if err != nil {
|
|
|
|
|
receiver.logger.Error("failed to send report to user on <GetHistoryById> of <HistoryService>",
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
zap.String("userID", tariffs.UserID),
|
|
|
|
|
)
|
|
|
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-23 14:34:45 +00:00
|
|
|
|
hlogger.Emit(models.InfoReportRequest{
|
|
|
|
|
CtxUserID: tariffs.UserID,
|
|
|
|
|
CtxAccountID: account.ID,
|
|
|
|
|
CtxID: req.Id,
|
|
|
|
|
CtxTariff: strings.Join(utils.GetTariffsIDs(tariffs.RawDetails.Tariffs), ","),
|
|
|
|
|
CtxOrgName: account.Name.Orgname,
|
|
|
|
|
})
|
2024-05-21 13:50:26 +00:00
|
|
|
|
|
2024-05-23 14:34:45 +00:00
|
|
|
|
return ctx.SendStatus(fiber.StatusOK)
|
2024-05-21 13:50:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (receiver *HistoryController) 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 {
|
|
|
|
|
receiver.logger.Error("failed to bind request", zap.Error(err))
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result, err := receiver.accountRepo.QuizLogoStat(ctx.Context(), repository.QuizLogoStatDeps{
|
|
|
|
|
Page: req.Page,
|
|
|
|
|
Limit: req.Limit,
|
|
|
|
|
From: req.From,
|
|
|
|
|
To: req.To,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting quiz logo stat", err.Error()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ctx.Status(fiber.StatusOK).JSON(result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (receiver *HistoryController) PromocodeLTV(ctx *fiber.Ctx) error {
|
|
|
|
|
var req struct {
|
|
|
|
|
From int `json:"from"`
|
|
|
|
|
To int `json:"to"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := ctx.BodyParser(&req); err != nil {
|
|
|
|
|
receiver.logger.Error("failed to bind request", zap.Error(err))
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// получаем мапу вида [promoID] = []{userid,timeActivate}
|
|
|
|
|
// отдаются только первые использованые на аккаунте промокоды, соответсвенно подсчет идет сугубо по ним
|
|
|
|
|
// если в запросе время различается с временем активации - если меньше, то учитывается только после применения
|
|
|
|
|
// если больше, то учитывается только с начала переданного from
|
|
|
|
|
codewordData, err := receiver.codewordClient.GetAllPromoActivations(ctx.Context(), &codeword_rpc.Time{
|
|
|
|
|
To: int64(req.To),
|
|
|
|
|
From: int64(req.From),
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting codeword data", err.Error()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
userSumMap, er := receiver.historyRepo.GetPayUsersPromoHistory(ctx.Context(), codewordData, int64(req.From), int64(req.To))
|
|
|
|
|
if er != nil {
|
|
|
|
|
return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed calculate promo users paid sum", er.Error()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp := make(map[string]struct {
|
|
|
|
|
Regs int
|
|
|
|
|
Money int64
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
for promoID, data := range codewordData {
|
|
|
|
|
fmt.Println("PROTOMOTO", promoID, data)
|
|
|
|
|
for _, value := range data {
|
|
|
|
|
|
|
|
|
|
paids, ok := userSumMap[value.UserID]
|
|
|
|
|
if !ok {
|
|
|
|
|
paids = 0
|
|
|
|
|
}
|
|
|
|
|
fmt.Println("PROTOMOTO1", paids, value)
|
|
|
|
|
|
|
|
|
|
if value.Time >= int64(req.From) && value.Time <= int64(req.To) {
|
|
|
|
|
if _, ok := resp[promoID]; !ok {
|
|
|
|
|
resp[promoID] = struct {
|
|
|
|
|
Regs int
|
|
|
|
|
Money int64
|
|
|
|
|
}{Regs: 1, Money: paids}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
current := resp[promoID]
|
|
|
|
|
current.Regs += 1
|
|
|
|
|
current.Money += paids
|
|
|
|
|
resp[promoID] = current
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ctx.Status(fiber.StatusOK).JSON(resp)
|
|
|
|
|
}
|