package wallet import ( "context" "fmt" "log" "go.uber.org/zap" "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/pkg/validate" ) // TODO: добавить интерфейс клиента сервиса оплаты type accountRepository interface { ChangeWallet(ctx context.Context, userID string, wallet *models.Wallet) (*models.Account, errors.Error) FindByUserID(ctx context.Context, id string) (*models.Account, errors.Error) } type currencyClient interface { Translate(context.Context, *models.TranslateCurrency) (int64, errors.Error) } type paymentService interface { GetPaymentLink(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) } type Deps struct { Logger *zap.Logger Repository accountRepository CurrencyClient currencyClient } type Service struct { logger *zap.Logger repository accountRepository currencyClient currencyClient } 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.CurrencyClient == nil { log.Panicln("CurrencyClient is nil on ") } return &Service{ logger: deps.Logger, repository: deps.Repository, currencyClient: deps.CurrencyClient, } } func (receiver *Service) ReplenishAccountWallet(ctx context.Context, request *models.ReplenishAccountWallet) (*models.Account, errors.Error) { if validate.IsStringEmpty(request.Account.Wallet.Currency) { return nil, errors.New( fmt.Errorf("currency of account <%s> is empty of ", request.Account.UserID), errors.ErrInternalError, ) } cash := request.Cash if request.Currency != request.Account.Wallet.Currency { translatedCash, translateErr := receiver.currencyClient.Translate(ctx, &models.TranslateCurrency{ Money: request.Cash, From: request.Currency, To: request.Account.Wallet.Currency, }) if translateErr != nil { receiver.logger.Error("failed to translate cash on of ", zap.Error(translateerr()), ) return nil, translateErr } cash = translatedCash } if request.Currency == models.InternalCurrencyKey { updatedAccount, changeErr := receiver.repository.ChangeWallet(ctx, request.Account.UserID, &models.Wallet{ Cash: request.Account.Wallet.Cash + cash, Money: request.Account.Wallet.Money + request.Cash, PurchasesAmount: request.Account.Wallet.PurchasesAmount + request.Cash, Currency: request.Account.Wallet.Currency, LastPaymentID: request.PaymentID, }) if changeErr != nil { receiver.logger.Error("failed to replenish wallet on of ", zap.Error(changeerr()), zap.String("Currency", request.Account.Wallet.Currency), zap.Int64("Money", request.Account.Wallet.Money+request.Cash), zap.Int64("Cash", request.Account.Wallet.Cash+cash), zap.Bool("Is currensy equal internal", request.Currency == models.InternalCurrencyKey), ) return nil, changeErr } return updatedAccount, nil } money, err := receiver.currencyClient.Translate(ctx, &models.TranslateCurrency{ Money: request.Cash, From: request.Currency, To: models.InternalCurrencyKey, }) if err != nil { receiver.logger.Error("failed to translate money on of ", zap.Error(err()), ) return nil, err } updatedAccount, err := receiver.repository.ChangeWallet(ctx, request.Account.UserID, &models.Wallet{ Cash: request.Account.Wallet.Cash + cash, Money: request.Account.Wallet.Money + money, PurchasesAmount: request.Account.Wallet.PurchasesAmount + money, Spent: request.Account.Wallet.Spent, Currency: request.Account.Wallet.Currency, LastPaymentID: request.PaymentID, }) if err != nil { receiver.logger.Error("failed to replenish wallet on of ", zap.Error(err()), zap.String("Currency", request.Account.Wallet.Currency), zap.Int64("Money", request.Account.Wallet.Money+request.Cash), zap.Int64("Cash", request.Account.Wallet.Cash+cash), zap.Bool("Is currensy equal internal", request.Currency == models.InternalCurrencyKey), ) return nil, err } return updatedAccount, nil } func (receiver *Service) WithdrawAccountWalletMoney(ctx context.Context, request *models.WithdrawAccountWallet) (*models.Account, errors.Error) { if validate.IsStringEmpty(request.Account.Wallet.Currency) { return nil, errors.New( fmt.Errorf("currency of account <%s> is empty of ", request.Account.UserID), errors.ErrInternalError, ) } cash, err := receiver.currencyClient.Translate(ctx, &models.TranslateCurrency{ Money: request.Money, From: models.InternalCurrencyKey, To: request.Account.Wallet.Currency, }) if err != nil { receiver.logger.Error("failed to translate money on of ", zap.Error(err()), ) return nil, err } updatedAccount, err := receiver.repository.ChangeWallet(ctx, request.Account.UserID, &models.Wallet{ Cash: request.Account.Wallet.Cash - cash, Money: request.Account.Wallet.Money - request.Money, Spent: request.Account.Wallet.Spent + request.Money, PurchasesAmount: request.Account.Wallet.PurchasesAmount, Currency: request.Account.Wallet.Currency, }) if err != nil { receiver.logger.Error("failed to replenish wallet on of ", zap.Error(err()), zap.String("Currency", request.Account.Wallet.Currency), zap.Int64("Money", request.Account.Wallet.Money-request.Money), zap.Int64("Cash", request.Account.Wallet.Cash+cash), ) return nil, err } return updatedAccount, nil } func (receiver *Service) ChangeCurrency(ctx context.Context, userID string, currency models.CurrencyKey) (*models.Account, errors.Error) { account, err := receiver.repository.FindByUserID(ctx, userID) if err != nil { receiver.logger.Error("failed to find account on of ", zap.Error(err()), zap.String("userID", userID), zap.Any("currency", currency), ) return nil, err } cash, err := receiver.currencyClient.Translate(ctx, &models.TranslateCurrency{ Money: account.Wallet.Cash, From: account.Wallet.Currency, To: currency, }) if err != nil { receiver.logger.Error("failed to translate currency on of ", zap.Error(err()), ) return nil, err } updatedAccount, err := receiver.repository.ChangeWallet(ctx, account.UserID, &models.Wallet{ Cash: cash, Currency: currency, Money: account.Wallet.Money, }) if err != nil { receiver.logger.Error("failed to update wallet on of ", zap.Error(err()), ) return nil, err } return updatedAccount, nil }