package grpc import ( "context" "fmt" "gitea.pena/PenaSide/treasurer/internal/models/yandex" "gitea.pena/PenaSide/treasurer/internal/payment_provider" "gitea.pena/PenaSide/treasurer/internal/utils" "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 } type PaymentController struct { logger *zap.Logger paymentProviders []payment_provider.PaymentProvider providerMap map[models.PaymentType][]payment_provider.PaymentProvider mu sync.RWMutex } 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), } for _, provider := range deps.PaymentProviders { for _, method := range provider.GetSupportedPaymentMethods() { controller.providerMap[method] = append(controller.providerMap[method], provider) } } return controller, nil } func (receiver *PaymentController) getProviderForPaymentMethod(method models.PaymentType) (payment_provider.PaymentProvider, errors.Error) { receiver.mu.RLock() defer receiver.mu.RUnlock() providers, exists := receiver.providerMap[method] if !exists || len(providers) == 0 { return nil, errors.NewWithMessage("no provider found for payment method", errors.ErrNotFound) } return providers[0], nil } func (receiver *PaymentController) createPayment(ctx context.Context, paymentType models.PaymentType, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { provider, err := receiver.getProviderForPaymentMethod(paymentType) if err != nil { receiver.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), }), } link, err := provider.CreateInvoice(ctx, request) if err != nil { receiver.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 (receiver *PaymentController) GetPaymentLinkBankCard(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { return receiver.createPayment(ctx, models.PaymentTypeBankCard, in) } func (receiver *PaymentController) GetPaymentLinkYooMoney(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { return receiver.createPayment(ctx, models.PaymentTypeYoomoney, in) } func (receiver *PaymentController) GetPaymentLinkTinkoff(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { return receiver.createPayment(ctx, models.PaymentTypeTinkoff, in) } func (receiver *PaymentController) GetPaymentLinkSBP(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { return receiver.createPayment(ctx, models.PaymentTypeSBP, in) } func (receiver *PaymentController) GetPaymentLinkSberPay(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { return receiver.createPayment(ctx, models.PaymentTypeSberPay, in) } func (receiver *PaymentController) GetPaymentLinkSberbankB2B(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { return receiver.createPayment(ctx, models.PaymentTypeSberB2B, in) }