package cart import ( "context" "fmt" "log" "time" "go.uber.org/zap" "google.golang.org/protobuf/types/known/timestamppb" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/discount" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils/transfer" ) type accountRepository interface { FindByUserID(ctx context.Context, id string) (*models.Account, errors.Error) AddItemToCart(ctx context.Context, userID, itemID string) (*models.Account, errors.Error) RemoveItemFromCart(ctx context.Context, userID, itemID string) (*models.Account, errors.Error) ClearCart(ctx context.Context, userID string) (*models.Account, errors.Error) } type hubadminClient interface { GetTariff(ctx context.Context, tariffID string) (*models.Tariff, errors.Error) GetTariffs(ctx context.Context, tarriffIDs []string) ([]models.Tariff, errors.Error) } type discountClient interface { Apply(context.Context, *discount.ApplyDiscountRequest) (*discount.ApplyDiscountResponse, errors.Error) } type walletService interface { ReplenishAccountWallet(context.Context, *models.ReplenishAccountWallet) (*models.Account, errors.Error) WithdrawAccountWalletMoney(context.Context, *models.WithdrawAccountWallet) (*models.Account, errors.Error) GetLinkToReplenishFunds(ctx context.Context, money int64) (string, errors.Error) } type Deps struct { Logger *zap.Logger Repository accountRepository HubadminClient hubadminClient DiscountClient discountClient WalletService walletService } type Service struct { logger *zap.Logger repository accountRepository hubadminClient hubadminClient discountClient discountClient walletService walletService } func New(deps *Deps) *Service { if deps == nil { log.Panicln("deps is nil on ") } if deps.Logger == nil { log.Panicln("logger is nil on ") } if deps.Repository == nil { log.Panicln("repository is nil on ") } if deps.HubadminClient == nil { log.Panicln("HubadminClient is nil on ") } if deps.DiscountClient == nil { log.Panicln("DiscountClient is nil on ") } if deps.WalletService == nil { log.Panicln("WalletService is nil on ") } return &Service{ logger: deps.Logger, repository: deps.Repository, hubadminClient: deps.HubadminClient, discountClient: deps.DiscountClient, walletService: deps.WalletService, } } func (receiver *Service) Remove(ctx context.Context, userID, itemID string) ([]string, errors.Error) { account, err := receiver.repository.RemoveItemFromCart(ctx, userID, itemID) if err != nil { receiver.logger.Error("failed to remove item from cart on of ", zap.Error(err)) return []string{}, err } return account.Cart, nil } func (receiver *Service) Add(ctx context.Context, userID, itemID string) ([]string, errors.Error) { tariff, err := receiver.hubadminClient.GetTariff(ctx, itemID) if err != nil { receiver.logger.Error("failed to get tariff on of ", zap.Error(err), zap.String("tariffID", itemID)) return []string{}, err } if tariff == nil { return []string{}, errors.New( fmt.Errorf("failed to get tariff <%s> on of : tariff not found", itemID), errors.ErrNotFound, ) } account, err := receiver.repository.AddItemToCart(ctx, userID, itemID) if err != nil { receiver.logger.Error("failed to add item to cart on of ", zap.Error(err)) return []string{}, err } return account.Cart, nil } func (receiver *Service) Pay(ctx context.Context, userID string) (string, errors.Error) { account, err := receiver.repository.FindByUserID(ctx, userID) if err != nil { receiver.logger.Error("failed to find account on of ", zap.String("userID", userID), zap.Error(err)) return "", err } tariffs, err := receiver.hubadminClient.GetTariffs(ctx, account.Cart) if err != nil { receiver.logger.Error("failed to get tarrifs on of ", zap.Strings("cart", account.Cart), zap.Error(err)) return "", err } tariffsAmount := utils.CalculateCartPurchasesAmount(tariffs) // TODO: убрать все конвертеры чисел: float64, int64 response, err := receiver.discountClient.Apply(ctx, &discount.ApplyDiscountRequest{ UserInformation: &discount.UserInformation{ ID: account.UserID, Type: string(account.Status), PurchasesAmount: float64(account.Wallet.PurchasesAmount), CartPurchasesAmount: float64(tariffsAmount), }, Products: transfer.TariffsToProductInformations(tariffs), Date: timestamppb.New(time.Now()), }) if err != nil { receiver.logger.Error("failed to discount on of ", zap.Error(err.Extract())) return "", err } if account.Wallet.Money < int64(response.Price) { link, err := receiver.walletService.GetLinkToReplenishFunds(ctx, int64(response.Price)-account.Wallet.Money) if err != nil { receiver.logger.Error("failed to get link to replenish funds on of ") return "", err } return link, nil } if _, err := receiver.walletService.WithdrawAccountWalletMoney(ctx, &models.WithdrawAccountWallet{ Money: int64(response.Price), Account: account, }); err != nil { receiver.logger.Error("failed to withdraw money on of ", zap.Error(err.Extract())) return "", err } if _, err := receiver.repository.ClearCart(ctx, account.UserID); err != nil { receiver.logger.Error("failed to clear cart on of ", zap.Error(err.Extract())) return "", err } return "", nil }