package yoomoney import ( "context" "encoding/json" "fmt" "gitea.pena/PenaSide/treasurer/internal/errors" "gitea.pena/PenaSide/treasurer/internal/models" "gitea.pena/PenaSide/treasurer/internal/models/yandex" "gitea.pena/PenaSide/treasurer/internal/payment_provider" "gitea.pena/PenaSide/treasurer/internal/utils" "github.com/go-resty/resty/v2" "github.com/gofiber/fiber/v2" "github.com/google/uuid" "go.uber.org/zap" "net/http" ) const ( ProviderName = "yoomoney" ) type Config struct { StoreID string `env:"YOOMONEY_STORE_ID"` SecretKey string `env:"YOOMONEY_SECRET_KEY"` WebhooksURL string `env:"YOOMONEY_WEBHOOKS_URL"` PaymentsURL string `env:"YOOMONEY_PAYMENTS_URL"` } type Provider struct { logger *zap.Logger config *Config httpClient *resty.Client repository PaymentRepository } type PaymentRepository interface { Insert(context.Context, *models.Payment) (*models.Payment, errors.Error) SetPaymentStatus(ctx context.Context, paymentID string, status models.PaymentStatus) (*models.Payment, errors.Error) SetPaymentComplete(ctx context.Context, paymentID string) (*models.Payment, errors.Error) } func New(logger *zap.Logger, config *Config, repository PaymentRepository) (*Provider, errors.Error) { return &Provider{ logger: logger, config: config, httpClient: resty.New(), repository: repository, }, nil } func (p *Provider) GetName() string { return ProviderName } func (p *Provider) GetSupportedPaymentMethods() []models.PaymentType { return []models.PaymentType{ models.PaymentTypeBankCard, models.PaymentTypeTinkoff, models.PaymentTypeSberPay, models.PaymentTypeYoomoney, models.PaymentTypeMobile, models.PaymentTypeSBP, models.PaymentTypeSberB2B, } } // todo func (p *Provider) CreateInvoice(ctx context.Context, request *payment_provider.PaymentRequest) (*payment_provider.PaymentResponse, errors.Error) { idempotenceKey := uuid.New().String() yandexPayment, err := p.httpClient.R(). SetContext(ctx). SetHeader("Content-Type", "application/json"). SetHeader("Idempotence-Key", idempotenceKey). SetHeader("Authorization", utils.ConvertYoomoneySercetsToAuth("Basic", p.config.StoreID, p.config.SecretKey)). SetBody(&yandex.CreatePaymentRequest[yandex.PaymentMethodType]{ Amount: yandex.Amount{ Value: utils.ConvertAmountToStringFloat(request.Amount), Currency: request.Currency, }, //Receipt: yandex.Receipt{ // TaxSystemCode: 2, //https://yookassa.ru/developers/payment-acceptance/receipts/54fz/other-services/parameters-values#tax-systems // Customer: request.Requisites.Customer, // Items: request.Requisites.Items, //}, PaymentMethodData: &yandex.PaymentMethodType{Type: models.YandexPaymentTypeMap[request.PaymentMethod]}, Confirmation: &yandex.CreateConfirmationRedirect{ Type: yandex.ConfirmationTypeRedirect, Locale: "ru_RU", ReturnURL: request.ReturnURL, Enforce: true, }, Capture: true, ClientIP: request.ClientIP, }). Post(p.config.PaymentsURL) if err != nil { p.logger.Error("failed to create payment", zap.Error(err), zap.String("payment_method", string(request.PaymentMethod))) return nil, errors.NewWithError(fmt.Errorf("failed to create payment: %w", err), errors.ErrInternalError) } if yandexPayment.StatusCode() != http.StatusOK { p.logger.Error("failed to create payment", zap.Int("status_code", yandexPayment.StatusCode()), zap.String("response", yandexPayment.String())) return nil, errors.NewWithMessage("failed to create payment", errors.ErrInternalError) } var payment yandex.Payment if err := json.Unmarshal(yandexPayment.Body(), &payment); err != nil { p.logger.Error("failed to unmarshal payment response", zap.Error(err)) return nil, errors.NewWithError(fmt.Errorf("failed to unmarshal payment response: %w", err), errors.ErrInternalError) } dbPayment, err := p.repository.Insert(ctx, &models.Payment{ UserID: request.UserID, PaymentID: payment.ID, IdempotencePaymentID: idempotenceKey, ClientIP: request.ClientIP, Currency: request.Currency, Amount: request.Amount, Type: request.PaymentMethod, Status: models.PaymentStatusMap[string(payment.Status)], Completed: false, RawPaymentBody: payment, CallbackHostGRPC: request.CallbackHostGRPC, }) if err != nil { p.logger.Error("failed to save payment to database", zap.Error(err)) return nil, errors.NewWithError(fmt.Errorf("failed to save payment to database: %w", err), errors.ErrInternalError) } return &payment_provider.PaymentResponse{ RedirectURL: payment.Confirmation.ConfirmationURL, Payment: dbPayment, }, nil } func (p *Provider) RegisterWebhookHandlers(router fiber.Router) { router.Post(p.config.WebhooksURL, p.handleWebhook) } func (p *Provider) handleWebhook(c *fiber.Ctx) error { return nil }