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 ") } if deps.Repository == nil { log.Panicln("repository is nil on ") } if deps.AuthClient == nil { log.Panicln("auth client is nil on ") } 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 of : %w", errors.ErrInternalError), errors.ErrInternalError, ) } count, err := receiver.repository.CountAll(ctx, dto) if err != nil { receiver.logger.Error("failed to count histories on of ", 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 of ", 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 of ", 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 of ") 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 of ", 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 of ") 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 of ", 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 of ", 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 of ", 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 of ", 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 of ", 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 }