customer/internal/service/history/history.go
2023-12-22 18:12:43 +03:00

273 lines
7.4 KiB
Go

package history
import (
"context"
"fmt"
"log"
"math"
"os"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/fields"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
)
type GetHistories struct {
Pagination *models.Pagination
Type *string
UserID string
}
func (receiver *GetHistories) BSON() bson.M {
query := bson.M{
fields.History.IsDeleted: false,
fields.History.Type: *receiver.Type,
}
return query
}
type historyRepository interface {
CountAll(context.Context, *GetHistories) (int64, errors.Error)
FindMany(context.Context, *GetHistories) ([]models.History, errors.Error)
Insert(context.Context, *models.History) (*models.History, errors.Error)
GetRecentTariffs(context.Context, string) ([]models.TariffID, errors.Error) // new
GetHistoryByID(context.Context, string) (*models.ReportHistory, errors.Error)
GetDocNumber(context.Context, string) (map[string]int, errors.Error)
CalculateCustomerLTV(ctx context.Context, from, to int64) (int64, errors.Error)
}
type authClient interface {
GetUser(ctx context.Context, userID string) (*models.User, errors.Error)
}
type verificationClient interface {
GetUser(ctx context.Context, userID string) (*models.Verification, errors.Error)
}
type temlategenClient interface {
SendData(ctx context.Context, data models.RespGeneratorService, fileContents []byte, email string) errors.Error
}
type Deps struct {
Logger *zap.Logger
Repository historyRepository
AuthClient authClient
VerificationClient verificationClient
TemlategenClient temlategenClient
}
type Service struct {
logger *zap.Logger
repository historyRepository
AuthClient authClient
VerificationClient verificationClient
TemlategenClient temlategenClient
}
func New(deps Deps) *Service {
if deps.Logger == nil {
log.Panicln("logger is nil on <New (history service)>")
}
if deps.Repository == nil {
log.Panicln("repository is nil on <New (history service)>")
}
if deps.AuthClient == nil {
log.Panicln("auth client is nil on <New (account service)>")
}
return &Service{
logger: deps.Logger,
repository: deps.Repository,
AuthClient: deps.AuthClient,
}
}
func (receiver *Service) GetHistoryList(ctx context.Context, dto *GetHistories) (*models.PaginationResponse[models.History], errors.Error) {
if dto == nil {
return nil, errors.New(
fmt.Errorf("pagination is nil on <GetHistoryList> of <HistoryService>: %w", errors.ErrInternalError),
errors.ErrInternalError,
)
}
count, err := receiver.repository.CountAll(ctx, dto)
if err != nil {
receiver.logger.Error("failed to count histories on <GetHistoryList> of <HistoryService>",
zap.Error(err),
)
return nil, err
}
if count == 0 {
return &models.PaginationResponse[models.History]{TotalPages: 0, Records: []models.History{}}, nil
}
totalPages := int64(math.Ceil(float64(count) / float64(dto.Pagination.Limit)))
histories, err := receiver.repository.FindMany(ctx, dto)
if err != nil {
receiver.logger.Error("failed to get historiy list on <GetHistoryList> of <HistoryService>",
zap.Error(err),
)
return nil, err
}
return &models.PaginationResponse[models.History]{
TotalPages: totalPages,
Records: histories,
}, nil
}
func (receiver *Service) CreateHistory(ctx context.Context, history *models.History) (*models.History, errors.Error) {
createdHistory, err := receiver.repository.Insert(ctx, history)
if err != nil {
receiver.logger.Error("failed to create history on <CreateHistory> of <HistoryService>", zap.Error(err))
return nil, err
}
return createdHistory, nil
}
// TODO:tests.
func (receiver *Service) GetRecentTariffs(ctx context.Context, userID string) ([]models.TariffID, errors.Error) {
if userID == "" {
receiver.logger.Error("user id is missing in <GetRecentTariffs> of <HistoryService>")
return nil, errors.New(
fmt.Errorf("user id is missing: %w", errors.ErrInvalidArgs),
errors.ErrInvalidArgs,
)
}
tariffs, err := receiver.repository.GetRecentTariffs(ctx, userID)
if err != nil {
receiver.logger.Error(
"failed to get recent tariffs in <GetRecentTariffs> of <HistoryService>",
zap.String("userId", userID),
zap.Error(err),
)
return nil, err
}
return tariffs, nil
}
func (receiver *Service) GetHistoryByID(ctx context.Context, historyID string) errors.Error {
if historyID == "" {
receiver.logger.Error("history id is missing in <GetHistoryById> of <HistoryService>")
return errors.New(
fmt.Errorf("history id is missing: %w", errors.ErrInvalidArgs),
errors.ErrInvalidArgs,
)
}
tariffs, err := receiver.repository.GetHistoryByID(ctx, historyID)
if err != nil {
receiver.logger.Error(
"failed to get history by id in <GetHistoryById> of <HistoryService>",
zap.String("historyID", historyID),
zap.Error(err),
)
return err
}
if tariffs.Key != models.CustomerHistoryKeyPayCart {
receiver.logger.Error(
"invalid history record key",
zap.String("historyID", historyID),
zap.Error(err),
)
return err
}
historyMap, err := receiver.repository.GetDocNumber(ctx, tariffs.UserID)
if err != nil {
receiver.logger.Error(
"failed to get history of sorting by date created in <GetDocNumber> of <HistoryService>",
zap.String("historyID", historyID),
zap.Error(err),
)
return err
}
verifuser, err := receiver.VerificationClient.GetUser(ctx, 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 err
}
if !verifuser.Accepted {
receiver.logger.Error(
"verification not accepted",
zap.String("userID", tariffs.UserID),
zap.Error(err),
)
return err
}
authuser, err := receiver.AuthClient.GetUser(ctx, 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 err
}
fileContents, readerr := os.ReadFile("./report.docx")
if readerr != nil {
return errors.New(
fmt.Errorf("failed to read file: %w", errors.ErrInternalError),
errors.ErrInternalError,
)
}
for _, tariff := range tariffs.RawDetails.Tariffs {
totalAmount := uint64(0)
for _, privilege := range tariff.Privileges {
totalAmount += privilege.Amount
}
data := models.RespGeneratorService{
DocNumber: historyMap[historyID] + 1,
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 = receiver.TemlategenClient.SendData(ctx, data, fileContents, authuser.Email)
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 err
}
}
return nil
}
func (receiver *Service) CalculateCustomerLTV(ctx context.Context, from, to int64) (int64, errors.Error) {
ltv, err := receiver.repository.CalculateCustomerLTV(ctx, from, to)
if err != nil {
receiver.logger.Error("failed to calculate LTV", zap.Error(err))
return 0, err
}
return ltv, nil
}