2023-05-19 07:09:04 +00:00
|
|
|
|
package cart
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2023-05-19 09:08:15 +00:00
|
|
|
|
"fmt"
|
2023-05-19 07:09:04 +00:00
|
|
|
|
"log"
|
2023-05-30 11:33:57 +00:00
|
|
|
|
"time"
|
2023-05-19 07:09:04 +00:00
|
|
|
|
|
|
|
|
|
"go.uber.org/zap"
|
2023-05-30 11:33:57 +00:00
|
|
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
2023-05-19 07:09:04 +00:00
|
|
|
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
|
|
|
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
2023-05-30 11:33:57 +00:00
|
|
|
|
"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"
|
2023-05-19 07:09:04 +00:00
|
|
|
|
)
|
|
|
|
|
|
2023-05-31 21:28:35 +00:00
|
|
|
|
// TODO: добавить интерфейс клиента сервиса оплаты
|
|
|
|
|
|
2023-05-19 07:09:04 +00:00
|
|
|
|
type accountRepository interface {
|
2023-05-30 11:33:57 +00:00
|
|
|
|
FindByUserID(ctx context.Context, id string) (*models.Account, errors.Error)
|
2023-05-19 07:09:04 +00:00
|
|
|
|
AddItemToCart(ctx context.Context, userID, itemID string) (*models.Account, errors.Error)
|
|
|
|
|
RemoveItemFromCart(ctx context.Context, userID, itemID string) (*models.Account, errors.Error)
|
2023-05-30 11:33:57 +00:00
|
|
|
|
ClearCart(ctx context.Context, userID string) (*models.Account, errors.Error)
|
2023-05-19 07:09:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 09:08:15 +00:00
|
|
|
|
type hubadminClient interface {
|
|
|
|
|
GetTariff(ctx context.Context, tariffID string) (*models.Tariff, errors.Error)
|
2023-05-30 11:33:57 +00:00
|
|
|
|
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)
|
2023-05-19 09:08:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 07:09:04 +00:00
|
|
|
|
type Deps struct {
|
2023-05-19 09:08:15 +00:00
|
|
|
|
Logger *zap.Logger
|
|
|
|
|
Repository accountRepository
|
|
|
|
|
HubadminClient hubadminClient
|
2023-05-30 11:33:57 +00:00
|
|
|
|
DiscountClient discountClient
|
|
|
|
|
WalletService walletService
|
2023-05-19 07:09:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Service struct {
|
2023-05-19 09:08:15 +00:00
|
|
|
|
logger *zap.Logger
|
|
|
|
|
repository accountRepository
|
|
|
|
|
hubadminClient hubadminClient
|
2023-05-30 11:33:57 +00:00
|
|
|
|
discountClient discountClient
|
|
|
|
|
walletService walletService
|
2023-05-19 07:09:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func New(deps *Deps) *Service {
|
|
|
|
|
if deps == nil {
|
|
|
|
|
log.Panicln("deps is nil on <New (cart service)>")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if deps.Logger == nil {
|
|
|
|
|
log.Panicln("logger is nil on <New (cart service)>")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if deps.Repository == nil {
|
|
|
|
|
log.Panicln("repository is nil on <New (cart service)>")
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 09:08:15 +00:00
|
|
|
|
if deps.HubadminClient == nil {
|
|
|
|
|
log.Panicln("HubadminClient is nil on <New (cart service)>")
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-30 11:33:57 +00:00
|
|
|
|
if deps.DiscountClient == nil {
|
|
|
|
|
log.Panicln("DiscountClient is nil on <New (cart service)>")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if deps.WalletService == nil {
|
|
|
|
|
log.Panicln("WalletService is nil on <New (cart service)>")
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 07:09:04 +00:00
|
|
|
|
return &Service{
|
2023-05-19 09:08:15 +00:00
|
|
|
|
logger: deps.Logger,
|
|
|
|
|
repository: deps.Repository,
|
|
|
|
|
hubadminClient: deps.HubadminClient,
|
2023-05-30 11:33:57 +00:00
|
|
|
|
discountClient: deps.DiscountClient,
|
|
|
|
|
walletService: deps.WalletService,
|
2023-05-19 07:09:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 <Remove> of <CartService>", zap.Error(err))
|
|
|
|
|
return []string{}, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return account.Cart, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (receiver *Service) Add(ctx context.Context, userID, itemID string) ([]string, errors.Error) {
|
2023-05-19 09:08:15 +00:00
|
|
|
|
tariff, err := receiver.hubadminClient.GetTariff(ctx, itemID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
receiver.logger.Error("failed to get tariff on <Add> of <CartService>", 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 <Add> of <CartService>: tariff not found", itemID),
|
|
|
|
|
errors.ErrNotFound,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-19 07:09:04 +00:00
|
|
|
|
account, err := receiver.repository.AddItemToCart(ctx, userID, itemID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
receiver.logger.Error("failed to add item to cart on <Add> of <CartService>", zap.Error(err))
|
|
|
|
|
return []string{}, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return account.Cart, nil
|
|
|
|
|
}
|
2023-05-30 11:33:57 +00:00
|
|
|
|
|
|
|
|
|
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 <Pay> of <CartService>", 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 <Pay> of <CartService>", 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,
|
2023-05-31 21:28:35 +00:00
|
|
|
|
Type: string(account.Status),
|
|
|
|
|
PurchasesAmount: float64(account.Wallet.PurchasesAmount),
|
|
|
|
|
CartPurchasesAmount: float64(tariffsAmount),
|
2023-05-30 11:33:57 +00:00
|
|
|
|
},
|
|
|
|
|
Products: transfer.TariffsToProductInformations(tariffs),
|
|
|
|
|
Date: timestamppb.New(time.Now()),
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
receiver.logger.Error("failed to discount on <Pay> of <CartService>", zap.Error(err.Extract()))
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if account.Wallet.Money < int64(response.Price) {
|
|
|
|
|
receiver.logger.Error("failed to pay on <Pay> of <CartService>: 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,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-31 21:28:35 +00:00
|
|
|
|
// TODO: изменить метод пополнения на метод вычитания средств с кошелька
|
2023-05-30 11:33:57 +00:00
|
|
|
|
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 <Pay> of <CartService>", zap.Error(err.Extract()))
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, err := receiver.repository.ClearCart(ctx, account.UserID); err != nil {
|
|
|
|
|
receiver.logger.Error("failed to clear cart on <Pay> of <CartService>", zap.Error(err.Extract()))
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|