codeword/internal/services/promocode_service.go
2024-01-27 15:51:32 +03:00

185 lines
6.0 KiB
Go

package services
import (
"codeword/internal/kafka/tariff"
"codeword/internal/models"
"codeword/internal/proto/discount"
"codeword/internal/utils/genID"
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.uber.org/zap"
)
type PromoCodeRepository interface {
CreatePromoCode(ctx context.Context, req *models.PromoCode) (*models.PromoCode, error)
EditPromoCode(ctx context.Context, req *models.ReqEditPromoCode) (*models.PromoCode, error)
GetPromoCodesList(ctx context.Context, req *models.GetPromoCodesListReq) ([]models.PromoCode, int64, error)
ActivatePromo(ctx context.Context, req *models.ActivateReq) (*models.PromoCode, error)
DeletePromoCode(ctx context.Context, promoCodeID string) error
GetPromoCodeByID(ctx context.Context, promoCodeID primitive.ObjectID) (*models.PromoCode, error)
AddFastLink(ctx context.Context, promoCodeID primitive.ObjectID, xid string) error
}
type PromoStatsRepository interface {
UpdateStatistics(ctx context.Context, key, userID string) error
GetAllStatistics(ctx context.Context) ([]models.PromoCodeStats, error)
}
type PromoDeps struct {
Logger *zap.Logger
PromoCodeRepo PromoCodeRepository
StatsRepo PromoStatsRepository
Kafka *tariff.Producer
DiscountClient discount.DiscountServiceClient
}
type PromoCodeService struct {
logger *zap.Logger
promoCodeRepo PromoCodeRepository
statsRepo PromoStatsRepository
kafka *tariff.Producer
discountClient discount.DiscountServiceClient
}
func NewPromoCodeService(deps PromoDeps) *PromoCodeService {
return &PromoCodeService{
logger: deps.Logger,
promoCodeRepo: deps.PromoCodeRepo,
statsRepo: deps.StatsRepo,
kafka: deps.Kafka,
discountClient: deps.DiscountClient,
}
}
func (s *PromoCodeService) CreatePromoCode(ctx context.Context, req *models.PromoCode) (*models.PromoCode, error) {
promoCode, err := s.promoCodeRepo.CreatePromoCode(ctx, req)
if err != nil {
s.logger.Error("Failed to add promocode in database", zap.Error(err))
return nil, err
}
return promoCode, nil
}
func (s *PromoCodeService) EditPromoCode(ctx context.Context, req *models.ReqEditPromoCode) (*models.PromoCode, error) {
editedPromoCode, err := s.promoCodeRepo.EditPromoCode(ctx, req)
if err != nil {
s.logger.Error("Failed to edit promocode in database", zap.Error(err))
return nil, err
}
return editedPromoCode, nil
}
func (s *PromoCodeService) GetPromoCodesList(ctx context.Context, req *models.GetPromoCodesListReq) ([]models.PromoCode, int64, error) {
promoCodes, count, err := s.promoCodeRepo.GetPromoCodesList(ctx, req)
if err != nil {
s.logger.Error("Failed to get list promocodes from database", zap.Error(err))
return nil, 0, err
}
return promoCodes, count, nil
}
// todo одумать еще реализацию этого дела, надо уточнить как разделяется ответственность в бонусе между привилегией и скидкой
// разделяется ли она или они всегда вместе, если разделяются то что-то из этого может быть пустым либо все заполеннное,
// соответсвенно надо сделать соответствующие проверки до записи в кафку и до отправки в дискаунт сервис
func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.ActivateReq) (string, error) {
promoCode, err := s.promoCodeRepo.ActivatePromo(ctx, req)
if err != nil {
s.logger.Error("Failed to activate promocode", zap.Error(err))
return "", err
}
err = s.statsRepo.UpdateStatistics(ctx, promoCode.ID.Hex(), req.UserID)
if err != nil {
s.logger.Error("Failed add in stats", zap.Error(err))
return "", err
}
var postfix string
if req.FastLink != "" {
postfix = fmt.Sprintf(":(%s)", req.FastLink)
}
var privileges []models.Privilege
privilege := models.Privilege{
PrivilegeID: promoCode.Bonus.Privilege.PrivilegeID,
Amount: promoCode.Bonus.Privilege.Amount,
}
privileges = append(privileges, privilege)
fakeTariff := &models.Tariff{
Name: promoCode.Codeword + postfix,
Privileges: privileges,
Deleted: promoCode.Delete,
CreatedAt: promoCode.CreatedAt,
}
if err := s.kafka.Send(ctx, req.UserID, fakeTariff); err != nil {
s.logger.Error("Failed to send fake tariff to Kafka", zap.Error(err))
return "", err
}
disOverHelm := true
discountRequest := &discount.CreateDiscountRequest{
Name: promoCode.Codeword + postfix,
Layer: promoCode.Bonus.Discount.Layer,
Description: "",
Condition: &discount.DiscountCondition{
Coupon: &promoCode.Codeword,
User: &req.UserID,
},
Target: &discount.DiscountCalculationTarget{
Factor: promoCode.Bonus.Discount.Factor,
Overhelm: &disOverHelm,
},
}
_, err = s.discountClient.CreateDiscount(ctx, discountRequest)
if err != nil {
s.logger.Error("Failed to create discount", zap.Error(err))
return "", err
}
return promoCode.Greetings, nil
}
func (s *PromoCodeService) DeletePromoCode(ctx context.Context, promoCodeID string) error {
err := s.promoCodeRepo.DeletePromoCode(ctx, promoCodeID)
if err != nil {
s.logger.Error("Failed simple delete promocode from database", zap.Error(err))
return err
}
return nil
}
func (s *PromoCodeService) CreateFastLink(ctx context.Context, promoCodeID string) (string, error) {
xid := genID.GenerateXID()
promoID, err := primitive.ObjectIDFromHex(promoCodeID)
if err != nil {
s.logger.Error("Failed conversion promoCodeID to ObjectID", zap.Error(err))
return "", err
}
err = s.promoCodeRepo.AddFastLink(ctx, promoID, xid)
if err != nil {
s.logger.Error("Failed to add fastlink for promocode by promocode id", zap.Error(err))
return "", err
}
return xid, nil
}
func (s *PromoCodeService) GetAllStats(ctx context.Context) ([]models.PromoCodeStats, error) {
promoStats, err := s.statsRepo.GetAllStatistics(ctx)
if err != nil {
s.logger.Error("Failed getting promo stats", zap.Error(err))
return nil, err
}
return promoStats, nil
}