From dfbff4d86bccfe493d3fffe1e1e85112a674596b Mon Sep 17 00:00:00 2001 From: pasha1coil Date: Wed, 11 Jun 2025 18:12:44 +0300 Subject: [PATCH] create CreateInvoice(ctx context.Context, request map[string]string) (string, errors.Error) and move rest payment to grpc --- internal/app/app.go | 2 +- internal/controller/grpc/payment.go | 240 ++++++------------ .../http_controllers/payment/payment.go | 85 ------- .../http_controllers/payment/route.go | 18 -- internal/initialize/controllers.go | 11 - internal/payment_provider/provider.go | 4 +- internal/service/webhook/yandex.go | 8 +- internal/utils/parse_map.go | 44 ++++ internal/utils/yoomoney.go | 22 +- internal/yoomoney/provider.go | 8 +- 10 files changed, 155 insertions(+), 287 deletions(-) delete mode 100644 internal/controller/http_controllers/payment/payment.go delete mode 100644 internal/controller/http_controllers/payment/route.go create mode 100644 internal/utils/parse_map.go diff --git a/internal/app/app.go b/internal/app/app.go index 4c74735..974deed 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -81,7 +81,7 @@ func Run(ctx context.Context, config initialize.Config, logger *zap.Logger) (app httpServer := http.NewServer(http.ServerConfig{ Logger: logger, - Controllers: []http.Controller{controllers.YandexStatusREST, controllers.PaymentREST}, + Controllers: []http.Controller{controllers.YandexStatusREST}, }) grpcServer, err := grpc.NewGRPC(logger) diff --git a/internal/controller/grpc/payment.go b/internal/controller/grpc/payment.go index 3661193..43b4726 100644 --- a/internal/controller/grpc/payment.go +++ b/internal/controller/grpc/payment.go @@ -2,28 +2,29 @@ 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/models/yandex" "gitea.pena/PenaSide/treasurer/internal/proto/treasurer" - "gitea.pena/PenaSide/treasurer/internal/utils" "go.uber.org/zap" ) -type PaymentService interface { - CreatePaymentBankCard(context.Context, *models.CreatePayment[yandex.Receipt]) (string, errors.Error) - CreatePayment(context.Context, *models.CreatePayment[yandex.Receipt]) (string, errors.Error) -} - type PaymentControllerDeps struct { - Logger *zap.Logger - PaymentService PaymentService + Logger *zap.Logger + PaymentProviders []payment_provider.PaymentProvider } type PaymentController struct { - logger *zap.Logger - paymentService PaymentService + logger *zap.Logger + paymentProviders []payment_provider.PaymentProvider + providerMap map[models.PaymentType][]payment_provider.PaymentProvider + mu sync.RWMutex } func NewPaymentController(deps PaymentControllerDeps) (*PaymentController, errors.Error) { @@ -31,169 +32,96 @@ func NewPaymentController(deps PaymentControllerDeps) (*PaymentController, error return nil, errors.NewWithMessage("Logger in nil on ", errors.ErrInvalidArgs) } - if deps.PaymentService == nil { - return nil, errors.NewWithMessage("PaymentService in nil on ", errors.ErrInvalidArgs) + if len(deps.PaymentProviders) == 0 { + return nil, errors.NewWithMessage("No payment providers provided on ", errors.ErrInvalidArgs) } - return &PaymentController{ - logger: deps.Logger, - paymentService: deps.PaymentService, - }, nil + 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(models.PaymentTypeBankCard), + "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) { - receiver.logger.Info("f of ", zap.Any("Customer", in.MainSettings.Customer)) - link, err := receiver.paymentService.CreatePaymentBankCard(ctx, &models.CreatePayment[yandex.Receipt]{ - Type: models.PaymentTypeBankCard, - Currency: in.MainSettings.Currency, - UserID: in.MainSettings.UserID, - ClientIP: in.MainSettings.ClientIP, - Amount: in.MainSettings.Amount, - CallbackHostGRPC: in.MainSettings.CallbackHostGRPC, - ReturnURL: in.MainSettings.ReturnURL, - Requisites: yandex.Receipt{ - TaxSystemCode: 2, - Customer: yandex.Customer{ - FullName: in.MainSettings.Customer.FullName, - Email: in.MainSettings.Customer.Email, - }, - Items: utils.ProtoItems2ReceiptItems(in.MainSettings.Items), - }, - }) - if err != nil { - receiver.logger.Error("failed to get payment link on of ", zap.Error(err)) - return nil, errors.GRPC("failed to get payment link", err) - } - - return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil + return receiver.createPayment(ctx, models.PaymentTypeBankCard, in) } func (receiver *PaymentController) GetPaymentLinkYooMoney(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { - link, err := receiver.paymentService.CreatePayment(ctx, &models.CreatePayment[yandex.Receipt]{ - Type: models.PaymentTypeYoomoney, - Currency: in.MainSettings.Currency, - UserID: in.MainSettings.UserID, - ClientIP: in.MainSettings.ClientIP, - Amount: in.MainSettings.Amount, - CallbackHostGRPC: in.MainSettings.CallbackHostGRPC, - ReturnURL: in.MainSettings.ReturnURL, - Requisites: yandex.Receipt{ - TaxSystemCode: 2, - Customer: yandex.Customer{ - FullName: in.MainSettings.Customer.FullName, - Email: in.MainSettings.Customer.Email, - }, - Items: utils.ProtoItems2ReceiptItems(in.MainSettings.Items), - }, - }) - if err != nil { - receiver.logger.Error("failed to get payment link on of ", zap.Error(err)) - return nil, errors.GRPC("failed to get payment link", err) - } - - return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil + return receiver.createPayment(ctx, models.PaymentTypeYoomoney, in) } func (receiver *PaymentController) GetPaymentLinkTinkoff(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { - link, err := receiver.paymentService.CreatePayment(ctx, &models.CreatePayment[yandex.Receipt]{ - Type: models.PaymentTypeTinkoff, - Currency: in.MainSettings.Currency, - UserID: in.MainSettings.UserID, - ClientIP: in.MainSettings.ClientIP, - Amount: in.MainSettings.Amount, - CallbackHostGRPC: in.MainSettings.CallbackHostGRPC, - ReturnURL: in.MainSettings.ReturnURL, - Requisites: yandex.Receipt{ - TaxSystemCode: 2, - Customer: yandex.Customer{ - FullName: in.MainSettings.Customer.FullName, - Email: in.MainSettings.Customer.Email, - }, - Items: utils.ProtoItems2ReceiptItems(in.MainSettings.Items), - }, - }) - if err != nil { - receiver.logger.Error("failed to get payment link on of ", zap.Error(err)) - return nil, errors.GRPC("failed to get payment link", err) - } - - return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil + return receiver.createPayment(ctx, models.PaymentTypeTinkoff, in) } func (receiver *PaymentController) GetPaymentLinkSBP(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { - link, err := receiver.paymentService.CreatePayment(ctx, &models.CreatePayment[yandex.Receipt]{ - Type: models.PaymentTypeSBP, - Currency: in.MainSettings.Currency, - UserID: in.MainSettings.UserID, - ClientIP: in.MainSettings.ClientIP, - Amount: in.MainSettings.Amount, - CallbackHostGRPC: in.MainSettings.CallbackHostGRPC, - ReturnURL: in.MainSettings.ReturnURL, - Requisites: yandex.Receipt{ - TaxSystemCode: 2, - Customer: yandex.Customer{ - FullName: in.MainSettings.Customer.FullName, - Email: in.MainSettings.Customer.Email, - }, - Items: utils.ProtoItems2ReceiptItems(in.MainSettings.Items), - }, - }) - if err != nil { - receiver.logger.Error("failed to get payment link on of ", zap.Error(err)) - return nil, errors.GRPC("failed to get payment link", err) - } - - return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil + return receiver.createPayment(ctx, models.PaymentTypeSBP, in) } func (receiver *PaymentController) GetPaymentLinkSberPay(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { - link, err := receiver.paymentService.CreatePayment(ctx, &models.CreatePayment[yandex.Receipt]{ - Type: models.PaymentTypeSberPay, - Currency: in.MainSettings.Currency, - UserID: in.MainSettings.UserID, - ClientIP: in.MainSettings.ClientIP, - Amount: in.MainSettings.Amount, - CallbackHostGRPC: in.MainSettings.CallbackHostGRPC, - ReturnURL: in.MainSettings.ReturnURL, - Requisites: yandex.Receipt{ - TaxSystemCode: 2, - Customer: yandex.Customer{ - FullName: in.MainSettings.Customer.FullName, - Email: in.MainSettings.Customer.Email, - }, - Items: utils.ProtoItems2ReceiptItems(in.MainSettings.Items), - }, - }) - if err != nil { - receiver.logger.Error("failed to get payment link on of ", zap.Error(err)) - return nil, errors.GRPC("failed to get payment link", err) - } - - return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil + return receiver.createPayment(ctx, models.PaymentTypeSberPay, in) } func (receiver *PaymentController) GetPaymentLinkSberbankB2B(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) { - link, err := receiver.paymentService.CreatePayment(ctx, &models.CreatePayment[yandex.Receipt]{ - Type: models.PaymentTypeSberB2B, - Currency: in.MainSettings.Currency, - UserID: in.MainSettings.UserID, - ClientIP: in.MainSettings.ClientIP, - Amount: in.MainSettings.Amount, - CallbackHostGRPC: in.MainSettings.CallbackHostGRPC, - ReturnURL: in.MainSettings.ReturnURL, - Requisites: yandex.Receipt{ - TaxSystemCode: 2, - Customer: yandex.Customer{ - FullName: in.MainSettings.Customer.FullName, - Email: in.MainSettings.Customer.Email, - }, - Items: utils.ProtoItems2ReceiptItems(in.MainSettings.Items), - }, - }) - if err != nil { - receiver.logger.Error("failed to get payment link on of ", zap.Error(err)) - return nil, errors.GRPC("failed to get payment link", err) - } - - return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil + return receiver.createPayment(ctx, models.PaymentTypeSberB2B, in) } diff --git a/internal/controller/http_controllers/payment/payment.go b/internal/controller/http_controllers/payment/payment.go deleted file mode 100644 index 9fc038b..0000000 --- a/internal/controller/http_controllers/payment/payment.go +++ /dev/null @@ -1,85 +0,0 @@ -package payment - -import ( - "fmt" - "gitea.pena/PenaSide/treasurer/internal/models/yandex" - "gitea.pena/PenaSide/treasurer/internal/payment_provider" - "github.com/gofiber/fiber/v2" - "sync" - - "gitea.pena/PenaSide/treasurer/internal/errors" - "gitea.pena/PenaSide/treasurer/internal/models" - "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 is 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 -} - -// TODO Добавить более сложную логику выбора провайдера (приоритеты, доступность и т.д.) -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 *fiber.Ctx) error { - var req models.CreatePayment[yandex.Receipt] - if err := ctx.BodyParser(&req); err != nil { - receiver.logger.Error("failed to parse payment request", zap.Error(err)) - return errors.HTTP(ctx, errors.NewWithError(fmt.Errorf("failed to parse input body: %w", err), errors.ErrInternalError)) - } - - provider, err := receiver.getProviderForPaymentMethod(req.Type) - if err != nil { - receiver.logger.Error("failed to get payment provider", zap.String("paymentMethod", string(req.Type)), zap.Error(err)) - return errors.HTTP(ctx, err) - } - - // todo потом нужно будет сделать так чтобы работало не только с yandex.Receipt - resp, err := provider.CreateInvoice(ctx.Context(), &req) - if err != nil { - receiver.logger.Error("failed to create payment", zap.String("provider", provider.GetName()), zap.Error(err)) - return errors.HTTP(ctx, err) - } - - return ctx.JSON(resp) -} diff --git a/internal/controller/http_controllers/payment/route.go b/internal/controller/http_controllers/payment/route.go deleted file mode 100644 index d4033c9..0000000 --- a/internal/controller/http_controllers/payment/route.go +++ /dev/null @@ -1,18 +0,0 @@ -package payment - -import "github.com/gofiber/fiber/v2" - -func (receiver *PaymentController) Register(router fiber.Router) { - // вебхуки для каждого провайдера - for _, provider := range receiver.paymentProviders { - provider.RegisterWebhookHandlers(router) - } - - // эндпоинт создания платежа - router.Post("/payment", receiver.CreatePayment) - -} - -func (receiver *PaymentController) Name() string { - return "" -} diff --git a/internal/initialize/controllers.go b/internal/initialize/controllers.go index a458da9..4a647d9 100644 --- a/internal/initialize/controllers.go +++ b/internal/initialize/controllers.go @@ -2,7 +2,6 @@ package initialize import ( "gitea.pena/PenaSide/treasurer/internal/controller/grpc" - "gitea.pena/PenaSide/treasurer/internal/controller/http_controllers/payment" "gitea.pena/PenaSide/treasurer/internal/controller/http_controllers/yandex" "gitea.pena/PenaSide/treasurer/internal/errors" "go.uber.org/zap" @@ -16,7 +15,6 @@ type ControllersDeps struct { type Controllers struct { YandexStatusREST *yandex.YandexStatusController PaymentGRPC *grpc.PaymentController - PaymentREST *payment.PaymentController } func NewControllers(deps ControllersDeps) (*Controllers, errors.Error) { @@ -30,14 +28,6 @@ func NewControllers(deps ControllersDeps) (*Controllers, errors.Error) { } paymentControllerGRPC, err := grpc.NewPaymentController(grpc.PaymentControllerDeps{ - Logger: deps.Logger, - PaymentService: deps.Services.Payment, - }) - if err != nil { - return nil, err - } - - paymentControllerREST, err := payment.NewPaymentController(payment.PaymentControllerDeps{ Logger: deps.Logger, PaymentProviders: deps.Services.PaymentProviders, }) @@ -48,6 +38,5 @@ func NewControllers(deps ControllersDeps) (*Controllers, errors.Error) { return &Controllers{ YandexStatusREST: yandexStatusControllerREST, PaymentGRPC: paymentControllerGRPC, - PaymentREST: paymentControllerREST, }, nil } diff --git a/internal/payment_provider/provider.go b/internal/payment_provider/provider.go index 3b9f52d..ad03aad 100644 --- a/internal/payment_provider/provider.go +++ b/internal/payment_provider/provider.go @@ -4,7 +4,6 @@ import ( "context" "gitea.pena/PenaSide/treasurer/internal/errors" "gitea.pena/PenaSide/treasurer/internal/models" - "gitea.pena/PenaSide/treasurer/internal/models/yandex" "github.com/gofiber/fiber/v2" ) @@ -12,6 +11,5 @@ type PaymentProvider interface { GetName() string RegisterWebhookHandlers(router fiber.Router) GetSupportedPaymentMethods() []models.PaymentType - // todo потом нужно будет сделать так чтобы работало не только с yandex.Receipt - CreateInvoice(ctx context.Context, request *models.CreatePayment[yandex.Receipt]) (string, errors.Error) + CreateInvoice(ctx context.Context, request map[string]string) (string, errors.Error) } diff --git a/internal/service/webhook/yandex.go b/internal/service/webhook/yandex.go index 17bd905..9e688c0 100644 --- a/internal/service/webhook/yandex.go +++ b/internal/service/webhook/yandex.go @@ -136,10 +136,10 @@ func (receiver *Yandex) SetWebhook(ctx context.Context, idempotenceKey string, r ) } - // if _, err := receiver.yandexWebhookClient.SetWebhookEvent(ctx, idempotenceKey, request); err != nil { - // receiver.logger.Error("failed to set webhook on of ", zap.Error(err)) - // return err - // } + //if _, err := receiver.yandexWebhookClient.SetWebhookEvent(ctx, idempotenceKey, request); err != nil { + // receiver.logger.Error("failed to set webhook on of ", zap.Error(err)) + // return err + //} return nil } diff --git a/internal/utils/parse_map.go b/internal/utils/parse_map.go new file mode 100644 index 0000000..94fce23 --- /dev/null +++ b/internal/utils/parse_map.go @@ -0,0 +1,44 @@ +package utils + +import ( + "encoding/json" + "fmt" + "gitea.pena/PenaSide/treasurer/internal/models" + "gitea.pena/PenaSide/treasurer/internal/models/yandex" + "strconv" + "strings" +) + +func MapToCreatePaymentYandexReceipt(data map[string]string) (*models.CreatePayment[yandex.Receipt], error) { + amount, err := strconv.ParseInt(data["amount"], 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid amount: %w", err) + } + + var callbackHosts []string + if val, ok := data["callback_host_grpc"]; ok && val != "" { + callbackHosts = strings.Split(val, ",") + } + + var requisites yandex.Receipt + if val, ok := data["requisites"]; ok && val != "" { + if err := json.Unmarshal([]byte(val), &requisites); err != nil { + return nil, fmt.Errorf("invalid requisites JSON: %w", err) + } + } else { + return nil, fmt.Errorf("missing requisites field") + } + + payment := &models.CreatePayment[yandex.Receipt]{ + Type: models.PaymentType(data["type"]), + Currency: data["currency"], + Amount: amount, + CallbackHostGRPC: callbackHosts, + ReturnURL: data["return_url"], + UserID: data["user_id"], + ClientIP: data["client_ip"], + Requisites: requisites, + } + + return payment, nil +} diff --git a/internal/utils/yoomoney.go b/internal/utils/yoomoney.go index bcc48ad..891a525 100644 --- a/internal/utils/yoomoney.go +++ b/internal/utils/yoomoney.go @@ -2,10 +2,11 @@ package utils import ( "encoding/base64" + "encoding/json" "fmt" - "strings" - "gitea.pena/PenaSide/treasurer/internal/proto/treasurer" "gitea.pena/PenaSide/treasurer/internal/models/yandex" + "gitea.pena/PenaSide/treasurer/internal/proto/treasurer" + "strings" ) func ConvertYoomoneySercetsToAuth(authType, storeID, secretKey string) string { @@ -20,14 +21,14 @@ func ProtoItem2ReceiptItem(in *treasurer.Item) yandex.Item { return yandex.Item{ Description: in.Description, Amount: yandex.ReceiptAmount{ - Value: in.Money, + Value: in.Money, Currency: in.Currency, }, - VatCode: 1, - Quantity: 1, - Measure: in.Measure, + VatCode: 1, + Quantity: 1, + Measure: in.Measure, PaymentSubject: "service", - PaymentMode: "full_prepayment", + PaymentMode: "full_prepayment", } } @@ -37,7 +38,12 @@ func ProtoItems2ReceiptItems(in []*treasurer.Item) []yandex.Item { for i, item := range in { out[i] = ProtoItem2ReceiptItem(item) - } + } return out } + +func ToJSON(v any) string { + b, _ := json.Marshal(v) + return string(b) +} diff --git a/internal/yoomoney/provider.go b/internal/yoomoney/provider.go index 60ee269..5ee8b36 100644 --- a/internal/yoomoney/provider.go +++ b/internal/yoomoney/provider.go @@ -71,7 +71,13 @@ func (p *Provider) GetSupportedPaymentMethods() []models.PaymentType { } } -func (p *Provider) CreateInvoice(ctx context.Context, request *models.CreatePayment[yandex.Receipt]) (string, errors.Error) { +// *models.CreatePayment[yandex.Receipt] +func (p *Provider) CreateInvoice(ctx context.Context, req map[string]string) (string, errors.Error) { + request, err := utils.MapToCreatePaymentYandexReceipt(req) + if err != nil { + p.logger.Error("failed to create payment yandex receipt by parse map", zap.Error(err)) + return "", errors.NewWithMessage("failed to parse input request by parse map", errors.ErrInvalidArgs) + } idempotenceKey := uuid.New().String() yandexPayment, err := p.httpClient.R().