customer/internal/service/wallet/wallet.go

254 lines
7.5 KiB
Go
Raw Normal View History

2023-05-22 12:43:15 +00:00
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"
)
2023-06-01 11:38:53 +00:00
// TODO: добавить интерфейс клиента сервиса оплаты
2023-05-22 12:43:15 +00:00
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 {
2023-05-22 16:42:15 +00:00
Translate(context.Context, *models.TranslateCurrency) (int64, errors.Error)
2023-05-22 12:43:15 +00:00
}
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 == nil {
log.Panicln("deps is nil on <New (wallet service)>")
}
if deps.Logger == nil {
log.Panicln("logger is nil on <New (v service)>")
}
if deps.Repository == nil {
log.Panicln("repository is nil on <New (wallet service)>")
}
if deps.CurrencyClient == nil {
log.Panicln("CurrencyClient is nil on <New (wallet service)>")
}
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) {
account, err := receiver.repository.FindByUserID(ctx, request.UserID)
if err != nil {
receiver.logger.Error("failed to find account on <ReplenishAccountWallet> of <WalletService>",
zap.Error(err.Extract()),
zap.String("userID", request.UserID),
)
return nil, err
}
if validate.IsStringEmpty(account.Wallet.Currency) {
return nil, errors.New(
fmt.Errorf("currency of account <%s> is empty <ReplenishAccountWallet> of <WalletService>", account.UserID),
errors.ErrInternalError,
)
}
2023-05-30 12:02:32 +00:00
cash := request.Cash
2023-05-22 12:43:15 +00:00
2023-05-30 12:02:32 +00:00
if request.Currency != account.Wallet.Currency {
translatedCash, translateErr := receiver.currencyClient.Translate(ctx, &models.TranslateCurrency{
Money: request.Cash,
From: request.Currency,
To: account.Wallet.Currency,
})
if translateErr != nil {
receiver.logger.Error("failed to translate cash on <ReplenishAccountWallet> of <WalletService>",
zap.Error(translateErr.Extract()),
)
return nil, translateErr
}
cash = translatedCash
2023-05-22 12:43:15 +00:00
}
if request.Currency == models.InternalCurrencyKey {
updatedAccount, changeErr := receiver.repository.ChangeWallet(ctx, account.UserID, &models.Wallet{
2023-05-31 21:28:35 +00:00
Cash: account.Wallet.Cash + cash,
Money: account.Wallet.Money + request.Cash,
PurchasesAmount: account.Wallet.PurchasesAmount + request.Cash,
Currency: account.Wallet.Currency,
2023-05-22 12:43:15 +00:00
})
if changeErr != nil {
receiver.logger.Error("failed to replenish wallet on <ReplenishAccountWallet> of <WalletService>",
zap.Error(changeErr.Extract()),
zap.String("Currency", account.Wallet.Currency),
2023-05-22 16:42:15 +00:00
zap.Int64("Money", account.Wallet.Money+request.Cash),
zap.Int64("Cash", account.Wallet.Cash+cash),
2023-05-22 12:43:15 +00:00
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 <ReplenishAccountWallet> of <WalletService>",
zap.Error(err.Extract()),
)
return nil, err
}
updatedAccount, err := receiver.repository.ChangeWallet(ctx, account.UserID, &models.Wallet{
2023-05-31 21:28:35 +00:00
Cash: account.Wallet.Cash + cash,
Money: account.Wallet.Money + money,
PurchasesAmount: account.Wallet.PurchasesAmount + money,
2023-06-01 11:38:53 +00:00
Spent: account.Wallet.Spent,
2023-05-31 21:28:35 +00:00
Currency: account.Wallet.Currency,
})
if err != nil {
receiver.logger.Error("failed to replenish wallet on <ReplenishAccountWallet> of <WalletService>",
zap.Error(err.Extract()),
zap.String("Currency", account.Wallet.Currency),
zap.Int64("Money", account.Wallet.Money+request.Cash),
zap.Int64("Cash", account.Wallet.Cash+cash),
zap.Bool("Is currensy equal internal", request.Currency == models.InternalCurrencyKey),
)
return nil, err
}
return updatedAccount, nil
}
2023-06-01 11:38:53 +00:00
func (receiver *Service) WithdrawAccountWalletMoney(ctx context.Context, request *models.WithdrawAccountWallet) (*models.Account, errors.Error) {
2023-05-31 21:28:35 +00:00
account, err := receiver.repository.FindByUserID(ctx, request.UserID)
if err != nil {
2023-06-01 11:38:53 +00:00
receiver.logger.Error("failed to find account on <WithdrawAccountWalletMoney> of <WalletService>",
2023-05-31 21:28:35 +00:00
zap.Error(err.Extract()),
zap.String("userID", request.UserID),
)
return nil, err
}
if validate.IsStringEmpty(account.Wallet.Currency) {
return nil, errors.New(
2023-06-01 11:38:53 +00:00
fmt.Errorf("currency of account <%s> is empty <WithdrawAccountWalletMoney> of <WalletService>", account.UserID),
2023-05-31 21:28:35 +00:00
errors.ErrInternalError,
)
}
2023-06-01 11:38:53 +00:00
cash, err := receiver.currencyClient.Translate(ctx, &models.TranslateCurrency{
Money: request.Money,
From: models.InternalCurrencyKey,
To: account.Wallet.Currency,
2023-05-31 21:28:35 +00:00
})
if err != nil {
2023-06-01 11:38:53 +00:00
receiver.logger.Error("failed to translate money on <WithdrawAccountWalletMoney> of <WalletService>",
2023-05-31 21:28:35 +00:00
zap.Error(err.Extract()),
)
return nil, err
}
updatedAccount, err := receiver.repository.ChangeWallet(ctx, account.UserID, &models.Wallet{
2023-06-01 11:38:53 +00:00
Cash: account.Wallet.Cash - cash,
Money: account.Wallet.Money - request.Money,
Spent: account.Wallet.Spent + request.Money,
PurchasesAmount: account.Wallet.PurchasesAmount,
2023-05-31 21:28:35 +00:00
Currency: account.Wallet.Currency,
2023-05-22 12:43:15 +00:00
})
if err != nil {
receiver.logger.Error("failed to replenish wallet on <ReplenishAccountWallet> of <WalletService>",
zap.Error(err.Extract()),
zap.String("Currency", account.Wallet.Currency),
2023-06-01 11:38:53 +00:00
zap.Int64("Money", account.Wallet.Money-request.Money),
2023-05-22 16:42:15 +00:00
zap.Int64("Cash", account.Wallet.Cash+cash),
2023-05-22 12:43:15 +00:00
)
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 <ChangeCurrency> of <WalletService>",
zap.Error(err.Extract()),
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 <ChangeCurrency> of <WalletService>",
zap.Error(err.Extract()),
)
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 <ChangeCurrency> of <WalletService>",
zap.Error(err.Extract()),
)
return nil, err
}
return updatedAccount, nil
}
2023-06-01 11:38:53 +00:00
func (receiver *Service) GetLinkToReplenishFunds(context.Context, int64) (string, errors.Error) {
return "", errors.New(
fmt.Errorf("failed to get link to replenish funds: %w", errors.ErrMethodNotImplemented),
errors.ErrMethodNotImplemented,
)
}