From 158d7ce9e25a9fa4779c5172086a1d716d3b96ce Mon Sep 17 00:00:00 2001 From: Pasha Date: Wed, 23 Jul 2025 17:50:22 +0300 Subject: [PATCH] added logic for CartPurchaseEvent todo need resolve coflict with accesToken --- internal/initialize/services.go | 5 + .../controller/grpc/payment/payment.go | 21 +- internal/service/callback/payment.go | 195 ++++++++++++++++-- 3 files changed, 201 insertions(+), 20 deletions(-) diff --git a/internal/initialize/services.go b/internal/initialize/services.go index 8df148d..271393e 100644 --- a/internal/initialize/services.go +++ b/internal/initialize/services.go @@ -60,6 +60,11 @@ func NewServices(deps ServicesDeps) *Services { Notifier: deps.Notifier, NotifyChannel: deps.NotificationChannel, AdminURL: deps.AdminURL, + HistoryRepo: deps.Repositories.HistoryRepository, + HubAdminClient: deps.Clients.HubadminClient, + DiscountClient: deps.Clients.DiscountClient, + CurrencyClient: deps.Clients.CurrencyClient, + Producer: deps.Brokers.TariffProducer, }), TariffBrokerService: tariffBrokerService, } diff --git a/internal/interface/controller/grpc/payment/payment.go b/internal/interface/controller/grpc/payment/payment.go index 710e57a..d885f9f 100644 --- a/internal/interface/controller/grpc/payment/payment.go +++ b/internal/interface/controller/grpc/payment/payment.go @@ -5,12 +5,12 @@ import ( "github.com/themakers/hlog" "log" - "go.uber.org/zap" - "google.golang.org/protobuf/types/known/emptypb" "gitea.pena/PenaSide/customer/internal/errors" "gitea.pena/PenaSide/customer/internal/models" "gitea.pena/PenaSide/customer/internal/proto/payment_callback" "gitea.pena/PenaSide/customer/internal/service/callback" + "go.uber.org/zap" + "google.golang.org/protobuf/types/known/emptypb" ) type Deps struct { @@ -23,6 +23,7 @@ type Controller struct { logger *zap.Logger paymentCallbackService *callback.PaymentCallbackService hLogger hlog.Logger + payment_callback.UnimplementedPaymentCallbackServiceServer } func New(deps Deps) *Controller { @@ -81,3 +82,19 @@ func (receiver *Controller) OnFailure(ctx context.Context, in *payment_callback. return &emptypb.Empty{}, nil } + +func (receiver *Controller) OnCartPurchase(ctx context.Context, in *payment_callback.Event) (*emptypb.Empty, error) { + if err := receiver.paymentCallbackService.CartPurchaseEvent(ctx, &models.PaymentEvent{ + Key: in.Key, + Message: in.Message, + PaymentID: in.Payment.PaymentID, + Currency: in.Payment.Currency, + Amount: in.Payment.Amount, + UserID: in.Payment.UserID, + }); err != nil { + receiver.logger.Error("failed to send failure event on of ", zap.Error(err)) + return nil, errors.GRPC("failed to send cart purchase event", err) + } + + return &emptypb.Empty{}, nil +} diff --git a/internal/service/callback/payment.go b/internal/service/callback/payment.go index 75db8ea..92b3d4c 100644 --- a/internal/service/callback/payment.go +++ b/internal/service/callback/payment.go @@ -2,12 +2,22 @@ package callback import ( "context" - "log" "fmt" + "gitea.pena/PenaSide/customer/internal/interface/broker/tariff" + "gitea.pena/PenaSide/customer/internal/interface/client" + "gitea.pena/PenaSide/customer/internal/interface/repository" + "gitea.pena/PenaSide/customer/internal/proto/discount" + "gitea.pena/PenaSide/customer/internal/utils" + "gitea.pena/PenaSide/customer/internal/utils/transfer" + "gitea.pena/PenaSide/customer/pkg/validate" + "google.golang.org/protobuf/types/known/timestamppb" + "log" + "sync" + "time" - "go.uber.org/zap" "gitea.pena/PenaSide/customer/internal/errors" "gitea.pena/PenaSide/customer/internal/models" + "go.uber.org/zap" tb "gopkg.in/tucnak/telebot.v2" ) @@ -25,22 +35,32 @@ type walletService interface { type PaymentCallbackServiceDeps struct { Logger *zap.Logger - AccountRepository accountRepository + AccountRepository *repository.AccountRepository WalletService walletService HistoryService historyService - Notifier *tb.Bot - NotifyChannel int64 - AdminURL string + Notifier *tb.Bot + NotifyChannel int64 + AdminURL string + HistoryRepo *repository.HistoryRepository + HubAdminClient *client.HubadminClient + DiscountClient *client.DiscountClient + CurrencyClient *client.CurrencyClient + Producer *tariff.Producer } type PaymentCallbackService struct { logger *zap.Logger - accountRepository accountRepository + accountRepository *repository.AccountRepository walletService walletService historyService historyService - notifier *tb.Bot - notifyChannel int64 - adminURL string + notifier *tb.Bot + notifyChannel int64 + adminURL string + historyRepo *repository.HistoryRepository + hubAdminClient *client.HubadminClient + discountClient *client.DiscountClient + currencyClient *client.CurrencyClient + producer *tariff.Producer } func NewPaymentCallbackService(deps PaymentCallbackServiceDeps) *PaymentCallbackService { @@ -65,9 +85,9 @@ func NewPaymentCallbackService(deps PaymentCallbackServiceDeps) *PaymentCallback accountRepository: deps.AccountRepository, walletService: deps.WalletService, historyService: deps.HistoryService, - notifier: deps.Notifier, - notifyChannel: deps.NotifyChannel, - adminURL: deps.AdminURL, + notifier: deps.Notifier, + notifyChannel: deps.NotifyChannel, + adminURL: deps.AdminURL, } } @@ -107,11 +127,11 @@ func (receiver *PaymentCallbackService) SuccessEvent(ctx context.Context, event return err } //}() -go func () { - if _, err := receiver.notifier.Send(tb.ChatID(receiver.notifyChannel), fmt.Sprintf(`Внесены деньги %.2f, пользователем %s`,float64(event.Amount/100), receiver.adminURL + "/users/" + account.UserID)); err != nil { - fmt.Println("TBOER", err) - } -}() + go func() { + if _, err := receiver.notifier.Send(tb.ChatID(receiver.notifyChannel), fmt.Sprintf(`Внесены деньги %.2f, пользователем %s`, float64(event.Amount/100), receiver.adminURL+"/users/"+account.UserID)); err != nil { + fmt.Println("TBOER", err) + } + }() return nil } @@ -128,3 +148,142 @@ func (receiver *PaymentCallbackService) FailureEvent(ctx context.Context, event return nil } + +func (receiver *PaymentCallbackService) CartPurchaseEvent(ctx context.Context, event *models.PaymentEvent) errors.Error { + account, err := receiver.accountRepository.FindByUserID(ctx, event.UserID) + if err != nil { + receiver.logger.Error("failed to get account on of ", zap.Error(err)) + return err + } + + if len(account.Cart) == 0 { + return nil + } + + tariffs, err := receiver.hubAdminClient.GetTariffs(ctx, accesToken, account.Cart) + if err != nil { + receiver.logger.Error("failed to get tariffs on of ", zap.Error(err)) + return err + } + + tariffsAmount := utils.CalculateCartPurchasesAmount(tariffs) + + discountResponse, err := receiver.discountClient.Apply(ctx, &discount.ApplyDiscountRequest{ + UserInformation: &discount.UserInformation{ + ID: account.UserID, + Type: string(account.Status), + PurchasesAmount: uint64(account.Wallet.Spent), + CartPurchasesAmount: tariffsAmount, + }, + Products: transfer.TariffsToProductInformations(tariffs), + Date: timestamppb.New(time.Now()), + }) + if err != nil { + receiver.logger.Error("failed to apply discount on of ", zap.Error(err)) + return err + } + + for _, applied := range discountResponse.AppliedDiscounts { + if applied.Condition.User != nil && *applied.Condition.User != "" { + _, err := receiver.discountClient.DeleteDiscount(ctx, &discount.GetDiscountByIDRequest{ + ID: applied.ID, + }) + if err != nil { + receiver.logger.Error("failed to delete discount on of ", zap.Error(err)) + return err + } + } + } + + request := models.WithdrawAccountWallet{ + Money: int64(discountResponse.Price), + Account: account, + } + + if validate.IsStringEmpty(request.Account.Wallet.Currency) { + request.Account.Wallet.Currency = models.InternalCurrencyKey + } + + if request.Account.Wallet.Currency == models.InternalCurrencyKey { + _, err = receiver.accountRepository.ChangeWallet(ctx, request.Account.UserID, &models.Wallet{ + Cash: request.Account.Wallet.Cash - request.Money, + 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 change wallet on of ", zap.Error(err)) + return err + } + } else { + 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 currency on of ", zap.Error(err)) + return err + } + + _, err = receiver.accountRepository.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 change wallet (non-internal currency) on of ", zap.Error(err)) + return err + } + } + + if _, err := receiver.historyRepo.Insert(ctx, &models.History{ + Key: models.CustomerHistoryKeyPayCart, + UserID: account.UserID, + Comment: "Успешная оплата корзины", + RawDetails: models.RawDetails{ + Tariffs: tariffs, + Price: int64(discountResponse.Price), + }, + }); err != nil { + receiver.logger.Error("failed to insert history on of ", zap.Error(err)) + return err + } + + sendErrors := make([]errors.Error, 0) + waitGroup := sync.WaitGroup{} + mutex := sync.Mutex{} + + for _, tariff := range tariffs { + waitGroup.Add(1) + + go func(currentTariff models.Tariff) { + defer waitGroup.Done() + + if err := receiver.producer.Send(ctx, account.UserID, ¤tTariff); err != nil { + mutex.Lock() + defer mutex.Unlock() + sendErrors = append(sendErrors, err) + } + }(tariff) + } + + waitGroup.Wait() + + if len(sendErrors) > 0 { + for _, err := range sendErrors { + receiver.logger.Error("failed to send tariffs to broker on of ", zap.Error(err)) + } + return errors.New(fmt.Errorf("failed to send tariffs to broker"), errors.ErrInternalError) + } + + if _, err := receiver.accountRepository.ClearCart(ctx, account.UserID); err != nil { + receiver.logger.Error("failed to clear cart on of ", zap.Error(err)) + return err + } + + return nil +}