package grpc import ( "context" "fmt" "gitea.pena/PenaSide/treasurer/internal/models/yandex" "gitea.pena/PenaSide/treasurer/internal/payment_provider" "gitea.pena/PenaSide/treasurer/internal/repository" "gitea.pena/PenaSide/treasurer/internal/utils" "google.golang.org/protobuf/types/known/emptypb" "strconv" "strings" "sync" "gitea.pena/PenaSide/treasurer/internal/errors" "gitea.pena/PenaSide/treasurer/internal/models" "gitea.pena/PenaSide/treasurer/internal/proto/treasurer" "go.uber.org/zap" ) type PaymentControllerDeps struct { Logger *zap.Logger PaymentProviders []payment_provider.PaymentProvider PaymentMethodRepository *repository.PaymentMethodRepository } type PaymentController struct { logger *zap.Logger paymentProviders []payment_provider.PaymentProvider paymentMethodRepository *repository.PaymentMethodRepository providerMap map[models.PaymentType][]payment_provider.PaymentProvider mu sync.RWMutex treasurer.UnimplementedTreasurerServiceServer } func NewPaymentController(deps PaymentControllerDeps) (*PaymentController, errors.Error) { if deps.Logger == nil { return nil, errors.NewWithMessage("Logger in nil on ", errors.ErrInvalidArgs) } if len(deps.PaymentProviders) == 0 { return nil, errors.NewWithMessage("No payment providers provided on ", errors.ErrInvalidArgs) } controller := &PaymentController{ logger: deps.Logger, paymentProviders: deps.PaymentProviders, providerMap: make(map[models.PaymentType][]payment_provider.PaymentProvider), paymentMethodRepository: deps.PaymentMethodRepository, } for _, provider := range deps.PaymentProviders { for _, method := range provider.GetSupportedPaymentMethods() { controller.providerMap[method] = append(controller.providerMap[method], provider) } } return controller, nil } func (r *PaymentController) getProviderForPaymentMethod(method models.PaymentType) (payment_provider.PaymentProvider, errors.Error) { r.mu.RLock() defer r.mu.RUnlock() providers, exists := r.providerMap[method] if !exists || len(providers) == 0 { return nil, errors.NewWithMessage("no provider found for payment method", errors.ErrNotFound) } return providers[0], nil } func (r *PaymentController) createPayment(ctx context.Context, paymentType models.PaymentType, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { provider, err := r.getProviderForPaymentMethod(paymentType) if err != nil { r.logger.Error("failed to get payment provider", zap.String("paymentMethod", string(paymentType)), zap.Error(err)) return nil, errors.GRPC("failed to get payment provider", err) } request := map[string]string{ "type": string(paymentType), "currency": in.MainSettings.Currency, "amount": fmt.Sprintf("%d", in.MainSettings.Amount), "callback_host_grpc": strings.Join(in.MainSettings.CallbackHostGRPC, ","), "return_url": in.MainSettings.ReturnURL, "user_id": in.MainSettings.UserID, "client_ip": in.MainSettings.ClientIP, "requisites": utils.ToJSON(yandex.Receipt{ TaxSystemCode: 2, Customer: yandex.Customer{ FullName: in.MainSettings.Customer.FullName, INN: in.MainSettings.Customer.INN, Email: in.MainSettings.Customer.Email, Phone: in.MainSettings.Customer.Phone, }, Items: utils.ProtoItems2ReceiptItems(in.MainSettings.Items), }), "save_payment_method": strconv.FormatBool(in.MainSettings.Auto), "recurrent": strconv.FormatBool(in.MainSettings.Recurrent), } link, err := provider.CreateInvoice(ctx, request) if err != nil { r.logger.Error("failed to create payment", zap.String("provider", provider.GetName()), zap.Error(err)) return nil, errors.GRPC("failed to create payment", err) } return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil } func (r *PaymentController) GetPaymentLinkBankCard(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { r.logger.Info("f of ", zap.Any("Customer", in.MainSettings.Customer)) return r.createPayment(ctx, models.PaymentTypeBankCard, in) } func (r *PaymentController) GetPaymentLinkYooMoney(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { return r.createPayment(ctx, models.PaymentTypeYoomoney, in) } func (r *PaymentController) GetPaymentLinkTinkoff(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { return r.createPayment(ctx, models.PaymentTypeTinkoff, in) } func (r *PaymentController) GetPaymentLinkSBP(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { return r.createPayment(ctx, models.PaymentTypeSBP, in) } func (r *PaymentController) GetPaymentLinkSberPay(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { return r.createPayment(ctx, models.PaymentTypeSberPay, in) } func (r *PaymentController) GetPaymentLinkSberbankB2B(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { return r.createPayment(ctx, models.PaymentTypeSberB2B, in) } func (r *PaymentController) DeleteSavedPaymentMethods(ctx context.Context, in *treasurer.DeleteSavedPaymentMethodsRequest) (*emptypb.Empty, error) { if in.UserID == "" { r.logger.Error("empty user id provided") return nil, errors.GRPC("user id is required", errors.NewWithMessage("user id is required", errors.ErrInvalidArgs)) } err := r.paymentMethodRepository.DeleteByUserID(ctx, in.UserID) if err != nil { r.logger.Error("failed to delete payment methods", zap.Error(err), zap.String("userId", in.UserID)) return nil, errors.GRPC("failed to delete payment methods", errors.NewWithMessage("failed to delete payment methods", errors.ErrInternalError)) } return &emptypb.Empty{}, nil }