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(ctx context.Context, request *models.ReplenishAccountWallet) (*models.Account, 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) 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) response, err := receiver.discountClient.Apply(ctx, &discount.ApplyDiscountRequest{ UserInformation: &discount.UserInformation{ ID: account.UserID, Type: "", // TODO: Добавить тип PurchasesAmount: 0, // TODO: Добавить CartPurchasesAmount: float64(tariffsAmount), // TODO: Перевести в int64 }, 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) { receiver.logger.Error("failed to pay on of : insufficient funds", zap.Int64("account money", account.Wallet.Money), zap.Int64("money before discount", tariffsAmount), zap.Float64("money after discount", response.Price), ) return errors.New( fmt.Errorf("failed to pay: %v", errors.ErrInsufficientFunds), errors.ErrInsufficientFunds, ) } if _, err := receiver.walletService.ReplenishAccountWallet(ctx, &models.ReplenishAccountWallet{ Cash: -int64(response.Price), Currency: account.Wallet.Currency, UserID: account.UserID, }); 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 }